From 94b3f9d74ece104f55c74bc59894d64cd50afcd7 Mon Sep 17 00:00:00 2001 From: jonalfarlinga Date: Mon, 7 Oct 2024 11:52:40 -0500 Subject: [PATCH 1/8] improved error handling in Parse and lower. --- examples/whois-client.go | 12 +++---- go.mod | 1 + go.sum | 2 ++ objects/objects.go | 20 +++++++++--- objects/oid.go | 17 ++++++++-- objects/primitive.go | 67 +++++++++++++++++++++++++++++++++------- objects/priority.go | 18 +++++++++-- objects/property.go | 18 +++++++++-- objects/tags.go | 30 ++++++++++++++---- parsing.go | 22 ++++++++++--- plumbing/apdu.go | 34 +++++++++++++++----- plumbing/bvlc.go | 16 ++++++++-- plumbing/npdu.go | 12 +++++-- services/iam.go | 50 +++++++++++++++++++++--------- 14 files changed, 251 insertions(+), 68 deletions(-) diff --git a/examples/whois-client.go b/examples/whois-client.go index 9ec4b99..30dc2ba 100644 --- a/examples/whois-client.go +++ b/examples/whois-client.go @@ -11,7 +11,6 @@ import ( "github.com/spf13/cobra" "github.com/ulbios/bacnet" - "github.com/ulbios/bacnet/common" "github.com/ulbios/bacnet/services" ) @@ -40,7 +39,7 @@ func whoIsExample(cmd *cobra.Command, args []string) { log.Fatalf("Failed to resolve UDP address: %s", err) } - ifaceAddrs, err := net.InterfaceAddrs() + _, err = net.InterfaceAddrs() if err != nil { log.Fatalf("couldn't get interface information: %v\n", err) } @@ -72,10 +71,11 @@ func whoIsExample(cmd *cobra.Command, args []string) { if err != nil { log.Fatalf("error reading incoming packet: %v\n", err) } - if !common.IsLocalAddr(ifaceAddrs, remoteAddr) { - break - } - log.Printf("got our own broadcast, back to listening...\n") + // if !common.IsLocalAddr(ifaceAddrs, remoteAddr) { + // break + // } + // log.Printf("got our own broadcast, back to listening...\n") + break } log.Printf("read %d bytes from %s: %x\n", nBytes, remoteAddr, replyRaw[:nBytes]) diff --git a/go.mod b/go.mod index 5c5387c..b231425 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.19 require ( github.com/google/go-cmp v0.5.0 + github.com/pkg/errors v0.9.1 github.com/spf13/cobra v1.7.0 ) diff --git a/go.sum b/go.sum index 946150b..b5dd525 100644 --- a/go.sum +++ b/go.sum @@ -3,6 +3,8 @@ github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= diff --git a/objects/objects.go b/objects/objects.go index 60d00c4..4ecad04 100644 --- a/objects/objects.go +++ b/objects/objects.go @@ -1,6 +1,9 @@ package objects import ( + "fmt" + + "github.com/pkg/errors" "github.com/ulbios/bacnet/common" ) @@ -33,14 +36,20 @@ const objLenMin int = 2 // UnmarshalBinary sets the values retrieved from byte sequence in a Object frame. func (o *Object) UnmarshalBinary(b []byte) error { if l := len(b); l < objLenMin { - return common.ErrTooShortToParse + return errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf("Unmarshal Object bin length %d, marshal length %d", l, objLenMin), + ) } o.TagNumber = b[0] >> 4 o.TagClass = common.IntToBool(int(b[0]) & 0x8 >> 3) o.Length = b[0] & 0x7 if l := len(b); l < int(o.Length) { - return common.ErrTooShortToParse + return errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf("Unmarshal Object bin length %d, marshal length %d", l, o.Length), + ) } o.Data = b[1:o.Length] @@ -52,7 +61,7 @@ func (o *Object) UnmarshalBinary(b []byte) error { func (o *Object) MarshalBinary() ([]byte, error) { b := make([]byte, o.MarshalLen()) if err := o.MarshalTo(b); err != nil { - return nil, err + return nil, errors.Wrap(err, "Marshal Object") } return b, nil @@ -61,7 +70,10 @@ func (o *Object) MarshalBinary() ([]byte, error) { // MarshalTo puts the byte sequence in the byte array given as b. func (o *Object) MarshalTo(b []byte) error { if len(b) < o.MarshalLen() { - return common.ErrTooShortToMarshalBinary + return errors.Wrap( + common.ErrTooShortToMarshalBinary, + fmt.Sprintf("Marshal Object bin length %d, marshal length %d", len(b), o.MarshalLen()), + ) } b[0] = o.TagNumber<<4 | uint8(common.BoolToInt(o.TagClass))<<3 | o.Length if o.Length > 0 { diff --git a/objects/oid.go b/objects/oid.go index 5301c14..a930fbc 100644 --- a/objects/oid.go +++ b/objects/oid.go @@ -2,7 +2,9 @@ package objects import ( "encoding/binary" + "fmt" + "github.com/pkg/errors" "github.com/ulbios/bacnet/common" ) @@ -16,17 +18,26 @@ func DecObjectIdentifier(rawPayload APDUPayload) (ObjectIdentifier, error) { rawObject, ok := rawPayload.(*Object) if !ok { - return decObjectId, common.ErrWrongPayload + return decObjectId, errors.Wrap( + common.ErrWrongPayload, + fmt.Sprintf("DecObjectIdentifier not ok: %T", rawPayload), + ) } switch rawObject.TagClass { case true: if rawObject.Length != 4 { - return decObjectId, common.ErrWrongStructure + return decObjectId, errors.Wrap( + common.ErrWrongStructure, + fmt.Sprintf("DecObjectIdentifier length: %d, tag class: %v", rawObject.Length, rawObject.TagClass), + ) } case false: if rawObject.Length != 4 || rawObject.TagNumber != TagBACnetObjectIdentifier { - return decObjectId, common.ErrWrongStructure + return decObjectId, errors.Wrap( + common.ErrWrongStructure, + fmt.Sprintf("DecObjectIdentifier length: %d, tag class: %v", rawObject.Length, rawObject.TagClass), + ) } } diff --git a/objects/primitive.go b/objects/primitive.go index 4a9f737..4e5d321 100644 --- a/objects/primitive.go +++ b/objects/primitive.go @@ -2,19 +2,27 @@ package objects import ( "encoding/binary" + "fmt" "math" + "github.com/pkg/errors" "github.com/ulbios/bacnet/common" ) func DecUnisgnedInteger(rawPayload APDUPayload) (uint32, error) { rawObject, ok := rawPayload.(*Object) if !ok { - return 0, common.ErrWrongPayload + return 0, errors.Wrap( + common.ErrWrongPayload, + fmt.Sprintf("DecUnisgnedInteger not ok: %v", rawPayload), + ) } if rawObject.TagNumber != TagUnsignedInteger || rawObject.TagClass { - return 0, common.ErrWrongStructure + return 0, errors.Wrap( + common.ErrWrongStructure, + fmt.Sprintf("DecUnisgnedInteger wrong tag number: %v", rawObject.TagNumber), + ) } switch rawObject.Length { @@ -28,7 +36,23 @@ func DecUnisgnedInteger(rawPayload APDUPayload) (uint32, error) { return binary.BigEndian.Uint32(rawObject.Data), nil } - return 0, common.ErrNotImplemented + return 0, errors.Wrap( + common.ErrNotImplemented, + fmt.Sprintf("DecUnisgnedInteger not implemented data: %v", rawObject.Data), + ) +} +func EncUnsignedInteger8(value uint8) *Object { + newObj := Object{} + + data := make([]byte, 1) + data[0] = value + + newObj.TagNumber = TagUnsignedInteger + newObj.TagClass = false + newObj.Data = data + newObj.Length = uint8(len(data)) + + return &newObj } func EncUnsignedInteger16(value uint16) *Object { @@ -41,18 +65,24 @@ func EncUnsignedInteger16(value uint16) *Object { newObj.TagClass = false newObj.Data = data newObj.Length = uint8(len(data)) - + return &newObj } func DecEnumerated(rawPayload APDUPayload) (uint32, error) { rawObject, ok := rawPayload.(*Object) if !ok { - return 0, common.ErrWrongPayload + return 0, errors.Wrap( + common.ErrWrongPayload, + fmt.Sprintf("DecEnumerated not ok %v", rawPayload), + ) } if rawObject.TagNumber != TagEnumerated || rawObject.TagClass { - return 0, common.ErrWrongStructure + return 0, errors.Wrap( + common.ErrWrongStructure, + fmt.Sprintf("DecEnumerated wrong tag number: %v", rawObject.TagNumber), + ) } switch rawObject.Length { @@ -66,7 +96,10 @@ func DecEnumerated(rawPayload APDUPayload) (uint32, error) { return binary.BigEndian.Uint32(rawObject.Data), nil } - return 0, common.ErrNotImplemented + return 0, errors.Wrap( + common.ErrNotImplemented, + fmt.Sprintf("DecEnumerated not implemented data: %v", rawObject.Data), + ) } func EncEnumerated(value uint8) *Object { @@ -86,11 +119,17 @@ func EncEnumerated(value uint8) *Object { func DecReal(rawPayload APDUPayload) (float32, error) { rawObject, ok := rawPayload.(*Object) if !ok { - return 0, common.ErrWrongPayload + return 0, errors.Wrap( + common.ErrWrongPayload, + fmt.Sprintf("DecReal not ok: %v", rawPayload), + ) } if rawObject.TagNumber != TagReal { - return 0, common.ErrWrongStructure + return 0, errors.Wrap( + common.ErrWrongStructure, + fmt.Sprintf("DecReal bad tag number: %v", rawObject.TagNumber), + ) } return math.Float32frombits(binary.BigEndian.Uint32(rawObject.Data)), nil @@ -113,11 +152,17 @@ func EncReal(value float32) *Object { func DecNull(rawPayload APDUPayload) (bool, error) { rawObject, ok := rawPayload.(*Object) if !ok { - return false, common.ErrWrongPayload + return false, errors.Wrap( + common.ErrWrongPayload, + fmt.Sprintf("DecNull not ok %v", rawPayload), + ) } if rawObject.TagNumber != TagReal { - return false, common.ErrWrongStructure + return false, errors.Wrap( + common.ErrWrongStructure, + fmt.Sprintf("DecNull bad tag number %v", rawObject.TagNumber), + ) } return rawObject.TagNumber == TagNull && !rawObject.TagClass && rawObject.Length == 0, nil diff --git a/objects/priority.go b/objects/priority.go index 289e1e3..4ec7b5c 100644 --- a/objects/priority.go +++ b/objects/priority.go @@ -1,23 +1,35 @@ package objects import ( + "fmt" + + "github.com/pkg/errors" "github.com/ulbios/bacnet/common" ) func DecPriority(rawPayload APDUPayload) (uint8, error) { rawObject, ok := rawPayload.(*Object) if !ok { - return 0, common.ErrWrongPayload + return 0, errors.Wrap( + common.ErrWrongPayload, + fmt.Sprintf("DecPriority not ok %v", rawPayload), + ) } switch rawObject.TagClass { case true: if rawObject.Length != 1 { - return 0, common.ErrWrongStructure + return 0, errors.Wrap( + common.ErrWrongStructure, + fmt.Sprintf("DecPriority length %d tag class %v", rawObject.Length, rawObject.TagClass), + ) } case false: if rawObject.Length != 1 || !rawObject.TagClass { - return 0, common.ErrWrongStructure + return 0, errors.Wrap( + common.ErrWrongStructure, + fmt.Sprintf("DecPriority length %d tag class %v", rawObject.Length, rawObject.TagClass), + ) } } diff --git a/objects/property.go b/objects/property.go index beca247..9088456 100644 --- a/objects/property.go +++ b/objects/property.go @@ -1,23 +1,35 @@ package objects import ( + "fmt" + + "github.com/pkg/errors" "github.com/ulbios/bacnet/common" ) func DecPropertyIdentifier(rawPayload APDUPayload) (uint8, error) { rawObject, ok := rawPayload.(*Object) if !ok { - return 0, common.ErrWrongPayload + return 0, errors.Wrap( + common.ErrWrongPayload, + fmt.Sprintf("DecPropertyIdentifier not ok %v", rawPayload), + ) } switch rawObject.TagClass { case true: if rawObject.Length != 1 { - return 0, common.ErrWrongStructure + return 0, errors.Wrap( + common.ErrWrongStructure, + fmt.Sprintf("DecPropertyIdentifier length %d tag class %v", rawObject.Length, rawObject.TagClass), + ) } case false: if rawObject.Length != 1 || !rawObject.TagClass { - return 0, common.ErrWrongStructure + return 0, errors.Wrap( + common.ErrWrongStructure, + fmt.Sprintf("DecPropertyIdentifier length %d tag class %v", rawObject.Length, rawObject.TagClass), + ) } } diff --git a/objects/tags.go b/objects/tags.go index de161c7..1437380 100644 --- a/objects/tags.go +++ b/objects/tags.go @@ -1,6 +1,9 @@ package objects import ( + "fmt" + + "github.com/pkg/errors" "github.com/ulbios/bacnet/common" ) @@ -20,14 +23,20 @@ func NewNamedTag(number uint8, class bool, name uint8) *NamedTag { func (n *NamedTag) UnmarshalBinary(b []byte) error { if l := len(b); l < objLenMin { - return common.ErrTooShortToParse + return errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf("Unmarshal NamedTag bin length %d, min length %d", l, objLenMin), + ) } n.TagNumber = b[0] >> 4 n.TagClass = common.IntToBool(int(b[0]) & 0x8 >> 3) n.Name = b[0] & 0x7 if l := len(b); l < 1 { - return common.ErrTooShortToParse + return errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf("Unmarshal NamedTag bin length %d", l), + ) } return nil @@ -36,7 +45,7 @@ func (n *NamedTag) UnmarshalBinary(b []byte) error { func (n *NamedTag) MarshalBinary() ([]byte, error) { b := make([]byte, n.MarshalLen()) if err := n.MarshalTo(b); err != nil { - return nil, err + return nil, errors.Wrap(err, "unable to marshal NamedTag") } return b, nil @@ -44,7 +53,10 @@ func (n *NamedTag) MarshalBinary() ([]byte, error) { func (n *NamedTag) MarshalTo(b []byte) error { if len(b) < n.MarshalLen() { - return common.ErrTooShortToMarshalBinary + return errors.Wrap( + common.ErrTooShortToMarshalBinary, + fmt.Sprintf("marshall NamedTag length %d is less than %d", len(b), n.MarshalLen()), + ) } b[0] = n.TagNumber<<4 | uint8(common.BoolToInt(n.TagClass))<<3 | n.Name @@ -58,7 +70,10 @@ func (n *NamedTag) MarshalLen() int { func DecOpeningTab(rawPayload APDUPayload) (bool, error) { rawTag, ok := rawPayload.(*NamedTag) if !ok { - return false, common.ErrWrongPayload + return false, errors.Wrap( + common.ErrWrongPayload, + fmt.Sprintf("DecOpeningTab not ok %T", rawPayload), + ) } return rawTag.Name == 0x6 && rawTag.TagClass, nil } @@ -76,7 +91,10 @@ func EncOpeningTag(tagN uint8) *NamedTag { func DecClosingTab(rawPayload APDUPayload) (bool, error) { rawTag, ok := rawPayload.(*NamedTag) if !ok { - return false, common.ErrWrongPayload + return false, errors.Wrap( + common.ErrWrongPayload, + fmt.Sprintf("DecClosingTab not ok %T", rawPayload), + ) } return rawTag.Name == 0x7 && rawTag.TagClass, nil } diff --git a/parsing.go b/parsing.go index 33f4c38..ada6cab 100644 --- a/parsing.go +++ b/parsing.go @@ -1,6 +1,9 @@ package bacnet import ( + "fmt" + + "github.com/pkg/errors" "github.com/ulbios/bacnet/common" "github.com/ulbios/bacnet/plumbing" "github.com/ulbios/bacnet/services" @@ -15,7 +18,10 @@ func combine(t, s uint8) uint16 { // Parse decodes the given bytes. func Parse(b []byte) (plumbing.BACnet, error) { if len(b) < bacnetLenMin { - return nil, common.ErrTooShortToParse + return nil, errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf("Parsing length %d", len(b)), + ) } var bvlc plumbing.BVLC @@ -25,12 +31,12 @@ func Parse(b []byte) (plumbing.BACnet, error) { offset := 0 if err := bvlc.UnmarshalBinary(b); err != nil { - return nil, err + return nil, errors.Wrap(err, fmt.Sprintf("Parsing BVLC %x", b)) } offset += bvlc.MarshalLen() if err := npdu.UnmarshalBinary(b[offset:]); err != nil { - return nil, err + return nil, errors.Wrap(err, fmt.Sprintf("Parsing NPDU %x", b[offset:])) } offset += npdu.MarshalLen() @@ -60,11 +66,17 @@ func Parse(b []byte) (plumbing.BACnet, error) { case combine(plumbing.Error<<4, 0): bacnet = services.NewError(&bvlc, &npdu) default: - return nil, common.ErrNotImplemented + return nil, errors.Wrap( + common.ErrNotImplemented, + fmt.Sprintf("Parsing service: %x", c), + ) } if err := bacnet.UnmarshalBinary(b); err != nil { - return nil, err + return nil, errors.Wrap( + err, + fmt.Sprintf("Parsing BACnet %x", b[offset:]), + ) } return bacnet, nil diff --git a/plumbing/apdu.go b/plumbing/apdu.go index ac05171..293815b 100644 --- a/plumbing/apdu.go +++ b/plumbing/apdu.go @@ -1,6 +1,9 @@ package plumbing import ( + "fmt" + + "github.com/pkg/errors" "github.com/ulbios/bacnet/common" "github.com/ulbios/bacnet/objects" ) @@ -28,7 +31,10 @@ func NewAPDU(t, s uint8, objs []objects.APDUPayload) *APDU { // UnmarshalBinary sets the values retrieved from byte sequence in a APDU frame. func (a *APDU) UnmarshalBinary(b []byte) error { if l := len(b); l < a.MarshalLen() { - return common.ErrTooShortToParse + return errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf("Unmarshal APDU bin length %d, marshal length %d", l, a.MarshalLen()), + ) } a.Type = b[0] >> 4 @@ -134,7 +140,10 @@ func (a *APDU) UnmarshalBinary(b []byte) error { // MarshalTo puts the byte sequence in the byte array given as b. func (a *APDU) MarshalTo(b []byte) error { if len(b) < a.MarshalLen() { - return common.ErrTooShortToMarshalBinary + return errors.Wrap( + common.ErrTooShortToMarshalBinary, + fmt.Sprintf("Marshal APDU bin length %d, marshal length %d", len(b), a.MarshalLen()), + ) } var offset int = 0 @@ -149,14 +158,17 @@ func (a *APDU) MarshalTo(b []byte) error { for _, o := range a.Objects { ob, err := o.MarshalBinary() if err != nil { - return err + return errors.Wrap(err, "Marshal APDU") } copy(b[offset:offset+o.MarshalLen()], ob) offset += int(o.MarshalLen()) if offset > a.MarshalLen() { - return common.ErrTooShortToMarshalBinary + return errors.Wrap( + common.ErrTooShortToMarshalBinary, + fmt.Sprintf("Marshal APDU bin length %d, marshal length %d", len(b), a.MarshalLen()), + ) } } } @@ -169,14 +181,17 @@ func (a *APDU) MarshalTo(b []byte) error { for _, o := range a.Objects { ob, err := o.MarshalBinary() if err != nil { - return err + return errors.Wrap(err, "Marshal APDU") } copy(b[offset:offset+o.MarshalLen()], ob) offset += o.MarshalLen() if offset > a.MarshalLen() { - return common.ErrTooShortToMarshalBinary + return errors.Wrap( + common.ErrTooShortToMarshalBinary, + fmt.Sprintf("Marshal APDU bin length %d, marshal length %d", len(b), a.MarshalLen()), + ) } } } @@ -191,14 +206,17 @@ func (a *APDU) MarshalTo(b []byte) error { for _, o := range a.Objects { ob, err := o.MarshalBinary() if err != nil { - return err + return errors.Wrap(err, "Marshal APDU") } copy(b[offset:offset+o.MarshalLen()], ob) offset += o.MarshalLen() if offset > a.MarshalLen() { - return common.ErrTooShortToMarshalBinary + return errors.Wrap( + common.ErrTooShortToMarshalBinary, + fmt.Sprintf("Marshal APDU bin length %d, marshal length %d", len(b), a.MarshalLen()), + ) } } } diff --git a/plumbing/bvlc.go b/plumbing/bvlc.go index 8d4829c..bbb7336 100644 --- a/plumbing/bvlc.go +++ b/plumbing/bvlc.go @@ -2,7 +2,9 @@ package plumbing import ( "encoding/binary" + "fmt" + "github.com/pkg/errors" "github.com/ulbios/bacnet/common" ) @@ -34,7 +36,12 @@ func NewBVLC(f uint8) *BVLC { // UnmarshalBinary sets the values retrieved from byte sequence in a BVLC frame. func (bvlc *BVLC) UnmarshalBinary(b []byte) error { if l := len(b); l < bvlc.MarshalLen() { - return common.ErrTooShortToParse + return errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf( + "Unmarshal BVLC bin length %d, marshal length %d", + l, bvlc.MarshalLen()), + ) } bvlc.Type = b[0] bvlc.Function = b[1] @@ -47,7 +54,7 @@ func (bvlc *BVLC) UnmarshalBinary(b []byte) error { func (bvlc *BVLC) MarshalBinary() ([]byte, error) { b := make([]byte, bvlc.MarshalLen()) if err := bvlc.MarshalTo(b); err != nil { - return nil, err + return nil, errors.Wrap(err, "unable to marshal BVLC") } return b, nil @@ -63,7 +70,10 @@ func (bvlc *BVLC) MarshalLen() int { // MarshalTo puts the byte sequence in the byte array given as b. func (bvlc *BVLC) MarshalTo(b []byte) error { if len(b) < bvlc.MarshalLen() { - return common.ErrTooShortToMarshalBinary + return errors.Wrap( + common.ErrTooShortToMarshalBinary, + fmt.Sprint("Marshal BVLC bin length %d, marshal length %d", len(b), bvlc.MarshalLen()), + ) } b[0] = byte(bvlc.Type) b[1] = byte(bvlc.Function) diff --git a/plumbing/npdu.go b/plumbing/npdu.go index 0d9bc6f..307e9b1 100644 --- a/plumbing/npdu.go +++ b/plumbing/npdu.go @@ -2,7 +2,9 @@ package plumbing import ( "encoding/binary" + "fmt" + "github.com/pkg/errors" "github.com/ulbios/bacnet/common" ) @@ -35,7 +37,10 @@ func (n *NPDU) SetControlFlags(nsduContain bool, dstSpecifier bool, srcSpecifier // UnmarshalBinary sets the values retrieved from byte sequence in a NPDU frame. func (n *NPDU) UnmarshalBinary(b []byte) error { if l := len(b); l < n.MarshalLen() { - return common.ErrTooShortToParse + return errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf("Unmarshal NPDU bin length %d, marshal length %d", l, n.MarshalLen()), + ) } n.Version = b[0] n.Control = b[1] @@ -51,7 +56,10 @@ func (n *NPDU) UnmarshalBinary(b []byte) error { // MarshalTo puts the byte sequence in the byte array given as b. func (n *NPDU) MarshalTo(b []byte) error { if len(b) < n.MarshalLen() { - return common.ErrTooShortToMarshalBinary + return errors.Wrap( + common.ErrTooShortToMarshalBinary, + fmt.Sprintf("Marshal NPDU bin length %d, marshal length %d", len(b), n.MarshalLen()), + ) } b[0] = n.Version b[1] = n.Control diff --git a/services/iam.go b/services/iam.go index dc8910b..1a16ab1 100644 --- a/services/iam.go +++ b/services/iam.go @@ -1,6 +1,9 @@ package services import ( + "fmt" + + "github.com/pkg/errors" "github.com/ulbios/bacnet/common" "github.com/ulbios/bacnet/objects" "github.com/ulbios/bacnet/plumbing" @@ -40,6 +43,7 @@ func NewUnconfirmedIAm(bvlc *plumbing.BVLC, npdu *plumbing.NPDU) *UnconfirmedIAm // TODO: Consider to implement parameter struct to an argment of New functions. APDU: plumbing.NewAPDU(plumbing.UnConfirmedReq, ServiceUnconfirmedIAm, IAmObjects(1, 1024, 0, 1)), } + fmt.Println("UnconfirmedIAm loaded") u.SetLength() return u @@ -48,22 +52,34 @@ func NewUnconfirmedIAm(bvlc *plumbing.BVLC, npdu *plumbing.NPDU) *UnconfirmedIAm // UnmarshalBinary sets the values retrieved from byte sequence in a UnconfirmedIAm frame. func (u *UnconfirmedIAm) UnmarshalBinary(b []byte) error { if l := len(b); l < u.MarshalLen() { - return common.ErrTooShortToParse + return errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf("Unmarshal UnconfirmedIAm bin length %d, marshal length %d", l, u.MarshalLen()), + ) } var offset int = 0 if err := u.BVLC.UnmarshalBinary(b[offset:]); err != nil { - return common.ErrTooShortToParse + return errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf("Unmarshal UIAm BVLC %x", b[offset:]), + ) } offset += u.BVLC.MarshalLen() if err := u.NPDU.UnmarshalBinary(b[offset:]); err != nil { - return common.ErrTooShortToParse + return errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf("Unmarshal UIAm NPDU %x", b[offset:]), + ) } offset += u.NPDU.MarshalLen() if err := u.APDU.UnmarshalBinary(b[offset:]); err != nil { - return common.ErrTooShortToParse + return errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf("Unmarshal UIAm APDU %x", b[offset:]), + ) } return nil @@ -73,7 +89,7 @@ func (u *UnconfirmedIAm) UnmarshalBinary(b []byte) error { func (u *UnconfirmedIAm) MarshalBinary() ([]byte, error) { b := make([]byte, u.MarshalLen()) if err := u.MarshalTo(b); err != nil { - return nil, err + return nil, errors.Wrap(err, "Marshal UnconfirmedIAm") } return b, nil } @@ -81,21 +97,24 @@ func (u *UnconfirmedIAm) MarshalBinary() ([]byte, error) { // MarshalTo puts the byte sequence in the byte array given as b. func (u *UnconfirmedIAm) MarshalTo(b []byte) error { if len(b) < u.MarshalLen() { - return common.ErrTooShortToMarshalBinary + return errors.Wrap( + common.ErrTooShortToMarshalBinary, + fmt.Sprintf("Marshal UnconfirmedIAm bin lenght %d, marshal length %d", len(b), u.MarshalLen()), + ) } var offset = 0 if err := u.BVLC.MarshalTo(b[offset:]); err != nil { - return err + return errors.Wrap(err, "Marshal UnconfirmedIAm") } offset += u.BVLC.MarshalLen() if err := u.NPDU.MarshalTo(b[offset:]); err != nil { - return err + return errors.Wrap(err, "Marshal UnconfirmedIAm") } offset += u.NPDU.MarshalLen() if err := u.APDU.MarshalTo(b[offset:]); err != nil { - return err + return errors.Wrap(err, "Marshal UnconfirmedIAm") } return nil @@ -119,7 +138,10 @@ func (u *UnconfirmedIAm) Decode() (UnconfirmedIAmDec, error) { decIAm := UnconfirmedIAmDec{} if len(u.APDU.Objects) != 4 { - return decIAm, common.ErrWrongObjectCount + return decIAm, errors.Wrap( + common.ErrWrongObjectCount, + fmt.Sprintf("Decode UnconfirmedIAm object count %d", len(u.APDU.Objects)), + ) } for i, obj := range u.APDU.Objects { @@ -127,25 +149,25 @@ func (u *UnconfirmedIAm) Decode() (UnconfirmedIAmDec, error) { case 0: objId, err := objects.DecObjectIdentifier(obj) if err != nil { - return decIAm, err + return decIAm, errors.Wrap(err, "Decode UnconfirmedIAm ObjectIdentifier") } decIAm.DeviceId = objId.InstanceNumber case 1: maxLen, err := objects.DecUnisgnedInteger(obj) if err != nil { - return decIAm, err + return decIAm, errors.Wrap(err, "Decode UnconfirmedIAm UnsignedInteger") } decIAm.MaxAPDULength = uint16(maxLen) case 2: segSupport, err := objects.DecEnumerated(obj) if err != nil { - return decIAm, err + return decIAm, errors.Wrap(err, "Decode UnconfirmedIAm Enumerated") } decIAm.SegmentationSupported = uint8(segSupport) case 3: vendorId, err := objects.DecUnisgnedInteger(obj) if err != nil { - return decIAm, err + return decIAm, errors.Wrap(err, "Decode UnconfirmedIAm UnsignedInteger") } decIAm.VendorId = uint16(vendorId) } From e283648b0b35239911921067cd6da26ba8257fd9 Mon Sep 17 00:00:00 2001 From: jonalfarlinga Date: Mon, 7 Oct 2024 12:32:40 -0500 Subject: [PATCH 2/8] initialized UnconfirmedIAm with 8 bit VendorID --- services/iam.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/services/iam.go b/services/iam.go index 1a16ab1..846b59b 100644 --- a/services/iam.go +++ b/services/iam.go @@ -30,7 +30,11 @@ func IAmObjects(insNum uint32, acceptedSize uint16, supportedSeg uint8, vendorID objs[0] = objects.EncObjectIdentifier(false, objects.TagBACnetObjectIdentifier, objects.ObjectTypeDevice, 321) objs[1] = objects.EncUnsignedInteger16(acceptedSize) objs[2] = objects.EncEnumerated(supportedSeg) - objs[3] = objects.EncUnsignedInteger16(vendorID) + if vendorID < 256 { + objs[3] = objects.EncUnsignedInteger8(uint8(vendorID)) + } else { + objs[3] = objects.EncUnsignedInteger16(vendorID) + } return objs } From d761397759dcc371ca4fd317239e4390754768c4 Mon Sep 17 00:00:00 2001 From: jonalfarlinga Date: Mon, 7 Oct 2024 12:43:10 -0500 Subject: [PATCH 3/8] linting --- services/iam.go | 1 - 1 file changed, 1 deletion(-) diff --git a/services/iam.go b/services/iam.go index 846b59b..a0ca6d3 100644 --- a/services/iam.go +++ b/services/iam.go @@ -47,7 +47,6 @@ func NewUnconfirmedIAm(bvlc *plumbing.BVLC, npdu *plumbing.NPDU) *UnconfirmedIAm // TODO: Consider to implement parameter struct to an argment of New functions. APDU: plumbing.NewAPDU(plumbing.UnConfirmedReq, ServiceUnconfirmedIAm, IAmObjects(1, 1024, 0, 1)), } - fmt.Println("UnconfirmedIAm loaded") u.SetLength() return u From ad7f032985260b976ac4f4af3f9f5bad44f965d7 Mon Sep 17 00:00:00 2001 From: jonalfarlinga Date: Mon, 7 Oct 2024 12:51:15 -0500 Subject: [PATCH 4/8] added error handling on CACK and lower. --- plumbing/bvlc.go | 2 +- services/cack.go | 56 +++++++++++++++++++++++++++++++++++++----------- 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/plumbing/bvlc.go b/plumbing/bvlc.go index bbb7336..2a5b70d 100644 --- a/plumbing/bvlc.go +++ b/plumbing/bvlc.go @@ -72,7 +72,7 @@ func (bvlc *BVLC) MarshalTo(b []byte) error { if len(b) < bvlc.MarshalLen() { return errors.Wrap( common.ErrTooShortToMarshalBinary, - fmt.Sprint("Marshal BVLC bin length %d, marshal length %d", len(b), bvlc.MarshalLen()), + fmt.Sprintf("Marshal BVLC bin length %d, marshal length %d", len(b), bvlc.MarshalLen()), ) } b[0] = byte(bvlc.Type) diff --git a/services/cack.go b/services/cack.go index d1919b0..b28c5a1 100644 --- a/services/cack.go +++ b/services/cack.go @@ -1,6 +1,9 @@ package services import ( + "fmt" + + "github.com/pkg/errors" "github.com/ulbios/bacnet/common" "github.com/ulbios/bacnet/objects" "github.com/ulbios/bacnet/plumbing" @@ -47,22 +50,34 @@ func NewComplexACK(bvlc *plumbing.BVLC, npdu *plumbing.NPDU) *ComplexACK { func (c *ComplexACK) UnmarshalBinary(b []byte) error { if l := len(b); l < c.MarshalLen() { - return common.ErrTooShortToParse + return errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf("Unmarshal ComplexACK bin length %d, marshal length %d", l, c.MarshalLen()), + ) } var offset int = 0 if err := c.BVLC.UnmarshalBinary(b[offset:]); err != nil { - return common.ErrTooShortToParse + return errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf("Unmarshal BVLC %x", b[offset:]), + ) } offset += c.BVLC.MarshalLen() if err := c.NPDU.UnmarshalBinary(b[offset:]); err != nil { - return common.ErrTooShortToParse + return errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf("Unmarshal NPDU %x", b[offset:]), + ) } offset += c.NPDU.MarshalLen() if err := c.APDU.UnmarshalBinary(b[offset:]); err != nil { - return common.ErrTooShortToParse + return errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf("Unmarshal APDU %x", b[offset:]), + ) } return nil @@ -71,28 +86,40 @@ func (c *ComplexACK) UnmarshalBinary(b []byte) error { func (c *ComplexACK) MarshalBinary() ([]byte, error) { b := make([]byte, c.MarshalLen()) if err := c.MarshalTo(b); err != nil { - return nil, err + return nil, errors.Wrap(err, "unable to marshal ComplexACK") } return b, nil } func (c *ComplexACK) MarshalTo(b []byte) error { if len(b) < c.MarshalLen() { - return common.ErrTooShortToMarshalBinary + return errors.Wrap( + common.ErrTooShortToMarshalBinary, + fmt.Sprintf("Marshal ComplexACK bin length %d, marshal length %d", len(b), c.MarshalLen()), + ) } var offset = 0 if err := c.BVLC.MarshalTo(b[offset:]); err != nil { - return err + return errors.Wrap( + err, + fmt.Sprintf("Marshal BVLC %x", b[offset:]), + ) } offset += c.BVLC.MarshalLen() if err := c.NPDU.MarshalTo(b[offset:]); err != nil { - return err + return errors.Wrap( + err, + fmt.Sprintf("Marshal NPDU %x", b[offset:]), + ) } offset += c.NPDU.MarshalLen() if err := c.APDU.MarshalTo(b[offset:]); err != nil { - return err + return errors.Wrap( + err, + fmt.Sprintf("Marshal APDU %x", b[offset:]), + ) } return nil @@ -114,7 +141,10 @@ func (c *ComplexACK) Decode() (ComplexACKDec, error) { decCACK := ComplexACKDec{} if len(c.APDU.Objects) != 3 { - return decCACK, common.ErrWrongObjectCount + return decCACK, errors.Wrap( + common.ErrWrongObjectCount, + fmt.Sprintf("ComplexACK object count %d", len(c.APDU.Objects)), + ) } for i, obj := range c.APDU.Objects { @@ -122,20 +152,20 @@ func (c *ComplexACK) Decode() (ComplexACKDec, error) { case 0: objId, err := objects.DecObjectIdentifier(obj) if err != nil { - return decCACK, err + return decCACK, errors.Wrap(err, "decode ComplexACK object case 0") } decCACK.ObjectType = objId.ObjectType decCACK.InstanceId = objId.InstanceNumber case 1: propId, err := objects.DecPropertyIdentifier(obj) if err != nil { - return decCACK, err + return decCACK, errors.Wrap(err, "decode ComplexACK object case 1") } decCACK.PropertyId = propId case 2: value, err := objects.DecReal(obj) if err != nil { - return decCACK, err + return decCACK, errors.Wrap(err, "decode ComplexACK object case 2") } decCACK.PresentValue = value } From 32aa9ad5c0ca824258a8c87a9969475b8fb5a053 Mon Sep 17 00:00:00 2001 From: jonalfarlinga Date: Tue, 8 Oct 2024 11:57:20 -0500 Subject: [PATCH 5/8] added debug output, added long input handling, string data handling --- common/error.go | 1 + examples/rp-client.go | 7 ++- objects/primitive.go | 32 ++++++++++- parsing.go | 9 ++-- plumbing/apdu.go | 17 +++++- services/cack.go | 120 +++++++++++++++++++++++++++++------------- 6 files changed, 142 insertions(+), 44 deletions(-) diff --git a/common/error.go b/common/error.go index 0e8032a..3fd8feb 100644 --- a/common/error.go +++ b/common/error.go @@ -16,4 +16,5 @@ var ( ErrWrongObjectCount = errors.New("wrong object count") ErrWrongStructure = errors.New("unexpected object structure") ErrWrongPayload = errors.New("wrong payload type") + ErrInvalidObjectType = errors.New("invalid object type") ) diff --git a/examples/rp-client.go b/examples/rp-client.go index 11dca9a..555b9ab 100644 --- a/examples/rp-client.go +++ b/examples/rp-client.go @@ -50,6 +50,8 @@ func ReadPropertyClientExample(cmd *cobra.Command, args []string) { } defer listenConn.Close() + listenConn.SetDeadline(time.Now().Add(5 * time.Second)) + mReadProperty, err := bacnet.NewReadProperty(rpObjectType, rpInstanceId, rpPropertyId) if err != nil { log.Fatalf("error generating initial ReadProperty: %v\n", err) @@ -65,6 +67,9 @@ func ReadPropertyClientExample(cmd *cobra.Command, args []string) { log.Printf("sent: %x", mReadProperty) nBytes, remoteAddr, err := listenConn.ReadFrom(replyRaw) + if err != nil { + log.Fatalf("error reading incoming packet: %v\n", err) + } log.Printf("read %d bytes from %s: %x\n", nBytes, remoteAddr, replyRaw[:nBytes]) @@ -87,7 +92,7 @@ func ReadPropertyClientExample(cmd *cobra.Command, args []string) { } log.Printf( - "decoded CACK reply:\n\tObject Type: %d\n\tInstance Id: %d\n\tProperty Id: %d\n\tValue: %f\n", + "decoded CACK reply:\n\tObject Type: %d\n\tInstance Id: %d\n\tProperty Id: %d\n\tValue: %v\n", decodedCACK.ObjectType, decodedCACK.InstanceId, decodedCACK.PropertyId, decodedCACK.PresentValue, ) diff --git a/objects/primitive.go b/objects/primitive.go index 4e5d321..f4e8bcc 100644 --- a/objects/primitive.go +++ b/objects/primitive.go @@ -9,6 +9,36 @@ import ( "github.com/ulbios/bacnet/common" ) +func DecString(rawPayload APDUPayload) (string, error) { + rawObject, ok := rawPayload.(*Object) + if !ok { + return "", errors.Wrap( + common.ErrWrongPayload, + fmt.Sprintf("DecString not ok: %v", rawPayload), + ) + } + + if rawObject.TagNumber != TagCharacterString || rawObject.TagClass { + return "", errors.Wrap( + common.ErrWrongStructure, + fmt.Sprintf("DecString wrong tag number: %v", rawObject.TagNumber), + ) + } + + return string(rawObject.Data), nil +} + +func EncString(value string) *Object { + newObj := Object{} + + newObj.TagNumber = TagCharacterString + newObj.TagClass = false + newObj.Data = []byte(value) + newObj.Length = uint8(len(newObj.Data)) + + return &newObj +} + func DecUnisgnedInteger(rawPayload APDUPayload) (uint32, error) { rawObject, ok := rawPayload.(*Object) if !ok { @@ -65,7 +95,7 @@ func EncUnsignedInteger16(value uint16) *Object { newObj.TagClass = false newObj.Data = data newObj.Length = uint8(len(data)) - + return &newObj } diff --git a/parsing.go b/parsing.go index ada6cab..735b483 100644 --- a/parsing.go +++ b/parsing.go @@ -2,6 +2,7 @@ package bacnet import ( "fmt" + "log" "github.com/pkg/errors" "github.com/ulbios/bacnet/common" @@ -34,12 +35,13 @@ func Parse(b []byte) (plumbing.BACnet, error) { return nil, errors.Wrap(err, fmt.Sprintf("Parsing BVLC %x", b)) } offset += bvlc.MarshalLen() - + log.Printf("BVLC %x\n", b[:offset]) if err := npdu.UnmarshalBinary(b[offset:]); err != nil { return nil, errors.Wrap(err, fmt.Sprintf("Parsing NPDU %x", b[offset:])) } offset += npdu.MarshalLen() - + log.Printf("NPDU %x\n", b[:offset]) + log.Printf("APDU %x\n", b[offset:]) var c uint16 switch b[offset] >> 4 & 0xFF { case plumbing.UnConfirmedReq: @@ -49,7 +51,7 @@ func Parse(b []byte) (plumbing.BACnet, error) { case plumbing.ComplexAck, plumbing.SimpleAck, plumbing.Error: c = combine(b[offset], 0) // We need to skip the PDU flags and the InvokeID } - + fmt.Printf("switch: %x\n", c) switch c { case combine(plumbing.UnConfirmedReq<<4, services.ServiceUnconfirmedWhoIs): bacnet = services.NewUnconfirmedWhoIs(&bvlc, &npdu) @@ -71,7 +73,6 @@ func Parse(b []byte) (plumbing.BACnet, error) { fmt.Sprintf("Parsing service: %x", c), ) } - if err := bacnet.UnmarshalBinary(b); err != nil { return nil, errors.Wrap( err, diff --git a/plumbing/apdu.go b/plumbing/apdu.go index 293815b..c97bc15 100644 --- a/plumbing/apdu.go +++ b/plumbing/apdu.go @@ -30,6 +30,7 @@ func NewAPDU(t, s uint8, objs []objects.APDUPayload) *APDU { // UnmarshalBinary sets the values retrieved from byte sequence in a APDU frame. func (a *APDU) UnmarshalBinary(b []byte) error { + fmt.Println("UnmarshalBinary APDU") if l := len(b); l < a.MarshalLen() { return errors.Wrap( common.ErrTooShortToParse, @@ -41,7 +42,7 @@ func (a *APDU) UnmarshalBinary(b []byte) error { a.Flags = b[0] & 0x7 var offset int = 1 - + fmt.Println("Type: ", a.Type) switch a.Type { case UnConfirmedReq: a.Service = b[offset] @@ -100,10 +101,13 @@ func (a *APDU) UnmarshalBinary(b []byte) error { a.Objects = objs } case ComplexAck, SimpleAck, Error: + fmt.Printf("case ACK/Err offset: %d\n", offset) a.InvokeID = b[offset] offset++ + fmt.Printf("InvokeID %x offset %d\n", a.InvokeID, offset) a.Service = b[offset] offset++ + fmt.Printf("Service %x offset %d\n", a.Service, offset) if len(b) > 3 { objs := []objects.APDUPayload{} for { @@ -113,9 +117,16 @@ func (a *APDU) UnmarshalBinary(b []byte) error { Length: b[offset] & 0x7, } + // Handle extended value case + if o.Length == 5 { + offset++ + o.Length = uint8(b[offset]) + } + // Drop tags so that they don't get in the way! if b[offset] == objects.TagOpening || b[offset] == objects.TagClosing { - offset++ + fmt.Print("tag opening/closing\n") + offset++ if offset >= len(b) { break } @@ -123,6 +134,7 @@ func (a *APDU) UnmarshalBinary(b []byte) error { } o.Data = b[offset+1 : offset+int(o.Length)+1] + fmt.Printf("APDU object %v\n data %x\n offset %d\n", o, o.Data, offset) objs = append(objs, &o) offset += int(o.Length) + 1 @@ -130,6 +142,7 @@ func (a *APDU) UnmarshalBinary(b []byte) error { break } } + fmt.Println("Objects: ", len(objs)) a.Objects = objs } } diff --git a/services/cack.go b/services/cack.go index b28c5a1..0678372 100644 --- a/services/cack.go +++ b/services/cack.go @@ -20,22 +20,43 @@ type ComplexACKDec struct { ObjectType uint16 InstanceId uint32 PropertyId uint8 - PresentValue float32 + PresentValue interface{} } -func ComplexACKObjects(objectType uint16, instN uint32, propertyId uint8, value float32) []objects.APDUPayload { +func ComplexACKObjects(objectType uint16, instN uint32, propertyId uint8, value interface{}) []objects.APDUPayload { objs := make([]objects.APDUPayload, 5) - + fmt.Println("ComplexACKObjects") objs[0] = objects.EncObjectIdentifier(true, 0, objectType, instN) objs[1] = objects.EncPropertyIdentifier(true, 1, propertyId) objs[2] = objects.EncOpeningTag(3) - objs[3] = objects.EncReal(value) - objs[4] = objects.EncClosingTag(3) + switch v := value.(type) { + case int: + objs[3] = objects.EncReal(float32(v)) + case uint8: + objs[3] = objects.EncUnsignedInteger8(v) + case uint16: + objs[3] = objects.EncUnsignedInteger16(v) + case float32: + objs[3] = objects.EncReal(v) + case string: + objs[3] = objects.EncString(v) + default: + panic( + fmt.Sprintf("Unsupported PresentValue type %T", value), + ) + } + + objs[4] = objects.EncClosingTag(3) + for _, o := range objs { + fmt.Printf("%v\n", o) + } + fmt.Println("ComplexACKObjects end") return objs } func NewComplexACK(bvlc *plumbing.BVLC, npdu *plumbing.NPDU) *ComplexACK { + fmt.Println("NewComplexACK") c := &ComplexACK{ BVLC: bvlc, NPDU: npdu, @@ -44,15 +65,17 @@ func NewComplexACK(bvlc *plumbing.BVLC, npdu *plumbing.NPDU) *ComplexACK { objects.ObjectTypeAnalogOutput, 1, objects.PropertyIdPresentValue, 0)), } c.SetLength() - + fmt.Printf("Type: %d, Service: %d\n", c.APDU.Type, c.APDU.Service) + fmt.Println("NewComplexACK end") return c } func (c *ComplexACK) UnmarshalBinary(b []byte) error { + fmt.Printf("unmarshalBinary %x\n", b) if l := len(b); l < c.MarshalLen() { return errors.Wrap( common.ErrTooShortToParse, - fmt.Sprintf("Unmarshal ComplexACK bin length %d, marshal length %d", l, c.MarshalLen()), + fmt.Sprintf("unmarshal ComplexACK bin length %d, marshal length %d", l, c.MarshalLen()), ) } @@ -60,7 +83,7 @@ func (c *ComplexACK) UnmarshalBinary(b []byte) error { if err := c.BVLC.UnmarshalBinary(b[offset:]); err != nil { return errors.Wrap( common.ErrTooShortToParse, - fmt.Sprintf("Unmarshal BVLC %x", b[offset:]), + fmt.Sprintf("unmarshal BVLC %x", b[offset:]), ) } offset += c.BVLC.MarshalLen() @@ -68,15 +91,17 @@ func (c *ComplexACK) UnmarshalBinary(b []byte) error { if err := c.NPDU.UnmarshalBinary(b[offset:]); err != nil { return errors.Wrap( common.ErrTooShortToParse, - fmt.Sprintf("Unmarshal NPDU %x", b[offset:]), + fmt.Sprintf("unmarshal NPDU %x", b[offset:]), ) } offset += c.NPDU.MarshalLen() + fmt.Printf("\n\nAPDU binary %x\n", b[offset+11:]) + if err := c.APDU.UnmarshalBinary(b[offset:]); err != nil { return errors.Wrap( common.ErrTooShortToParse, - fmt.Sprintf("Unmarshal APDU %x", b[offset:]), + fmt.Sprintf("unmarshal APDU %x", b[offset:]), ) } @@ -95,14 +120,14 @@ func (c *ComplexACK) MarshalTo(b []byte) error { if len(b) < c.MarshalLen() { return errors.Wrap( common.ErrTooShortToMarshalBinary, - fmt.Sprintf("Marshal ComplexACK bin length %d, marshal length %d", len(b), c.MarshalLen()), + fmt.Sprintf("marshal ComplexACK bin length %d, marshal length %d", len(b), c.MarshalLen()), ) } var offset = 0 if err := c.BVLC.MarshalTo(b[offset:]); err != nil { return errors.Wrap( err, - fmt.Sprintf("Marshal BVLC %x", b[offset:]), + fmt.Sprintf("marshal BVLC %x", b[offset:]), ) } offset += c.BVLC.MarshalLen() @@ -110,7 +135,7 @@ func (c *ComplexACK) MarshalTo(b []byte) error { if err := c.NPDU.MarshalTo(b[offset:]); err != nil { return errors.Wrap( err, - fmt.Sprintf("Marshal NPDU %x", b[offset:]), + fmt.Sprintf("marshal NPDU %x", b[offset:]), ) } offset += c.NPDU.MarshalLen() @@ -118,7 +143,7 @@ func (c *ComplexACK) MarshalTo(b []byte) error { if err := c.APDU.MarshalTo(b[offset:]); err != nil { return errors.Wrap( err, - fmt.Sprintf("Marshal APDU %x", b[offset:]), + fmt.Sprintf("marshal APDU %x", b[offset:]), ) } @@ -143,32 +168,55 @@ func (c *ComplexACK) Decode() (ComplexACKDec, error) { if len(c.APDU.Objects) != 3 { return decCACK, errors.Wrap( common.ErrWrongObjectCount, - fmt.Sprintf("ComplexACK object count %d", len(c.APDU.Objects)), + fmt.Sprintf("complexACK object count %d", len(c.APDU.Objects)), ) } for i, obj := range c.APDU.Objects { - switch i { - case 0: - objId, err := objects.DecObjectIdentifier(obj) - if err != nil { - return decCACK, errors.Wrap(err, "decode ComplexACK object case 0") - } - decCACK.ObjectType = objId.ObjectType - decCACK.InstanceId = objId.InstanceNumber - case 1: - propId, err := objects.DecPropertyIdentifier(obj) - if err != nil { - return decCACK, errors.Wrap(err, "decode ComplexACK object case 1") - } - decCACK.PropertyId = propId - case 2: - value, err := objects.DecReal(obj) - if err != nil { - return decCACK, errors.Wrap(err, "decode ComplexACK object case 2") - } - decCACK.PresentValue = value - } + enc_obj, ok := obj.(*objects.Object) + if !ok { + return decCACK, errors.Wrap( + common.ErrInvalidObjectType, + fmt.Sprintf("ComplexACK object at index %d is not Object type", i), + ) + } + fmt.Printf( + "Object i %d tagnum %d tagclass %v data %x\n", + i, enc_obj.TagNumber, enc_obj.TagClass, enc_obj.Data, + ) + if enc_obj.TagClass { + switch enc_obj.TagNumber { + case 0: + objId, err := objects.DecObjectIdentifier(obj) + if err != nil { + return decCACK, errors.Wrap(err, "decode Context object case 0") + } + decCACK.ObjectType = objId.ObjectType + decCACK.InstanceId = objId.InstanceNumber + case 1: + propId, err := objects.DecPropertyIdentifier(obj) + if err != nil { + return decCACK, errors.Wrap(err, "decode Context object case 1") + } + decCACK.PropertyId = propId + } + } else { + switch enc_obj.TagNumber { + case 4: + value, err := objects.DecReal(obj) + if err != nil { + return decCACK, errors.Wrap(err, "decode Application object case 4") + } + decCACK.PresentValue = value + case 7: + value, err := objects.DecString(obj) + if err != nil { + return decCACK, errors.Wrap(err, "decode Application object case 7") + } + fmt.Printf("String value %s\n", value) + decCACK.PresentValue = value + } + } } return decCACK, nil From 63c4c5d06f505c235b3d77f0f533203ac8b0f31a Mon Sep 17 00:00:00 2001 From: jonalfarlinga Date: Wed, 9 Oct 2024 08:47:56 -0500 Subject: [PATCH 6/8] reverted non-error changes --- common/error.go | 1 - examples/rp-client.go | 5 +- examples/whois-client.go | 11 +++-- objects/primitive.go | 43 ----------------- parsing.go | 8 ++-- plumbing/apdu.go | 14 ------ services/cack.go | 99 ++++++++++------------------------------ services/iam.go | 6 +-- 8 files changed, 37 insertions(+), 150 deletions(-) diff --git a/common/error.go b/common/error.go index 3fd8feb..0e8032a 100644 --- a/common/error.go +++ b/common/error.go @@ -16,5 +16,4 @@ var ( ErrWrongObjectCount = errors.New("wrong object count") ErrWrongStructure = errors.New("unexpected object structure") ErrWrongPayload = errors.New("wrong payload type") - ErrInvalidObjectType = errors.New("invalid object type") ) diff --git a/examples/rp-client.go b/examples/rp-client.go index 555b9ab..e396d8b 100644 --- a/examples/rp-client.go +++ b/examples/rp-client.go @@ -50,8 +50,6 @@ func ReadPropertyClientExample(cmd *cobra.Command, args []string) { } defer listenConn.Close() - listenConn.SetDeadline(time.Now().Add(5 * time.Second)) - mReadProperty, err := bacnet.NewReadProperty(rpObjectType, rpInstanceId, rpPropertyId) if err != nil { log.Fatalf("error generating initial ReadProperty: %v\n", err) @@ -60,6 +58,7 @@ func ReadPropertyClientExample(cmd *cobra.Command, args []string) { replyRaw := make([]byte, 1024) sentRequests := 0 for { + listenConn.SetDeadline(time.Now().Add(5 * time.Second)) if _, err := listenConn.WriteTo(mReadProperty, remoteUDPAddr); err != nil { log.Fatalf("Failed to write the request: %s\n", err) } @@ -92,7 +91,7 @@ func ReadPropertyClientExample(cmd *cobra.Command, args []string) { } log.Printf( - "decoded CACK reply:\n\tObject Type: %d\n\tInstance Id: %d\n\tProperty Id: %d\n\tValue: %v\n", + "decoded CACK reply:\n\tObject Type: %d\n\tInstance Id: %d\n\tProperty Id: %d\n\tValue: %v\f", decodedCACK.ObjectType, decodedCACK.InstanceId, decodedCACK.PropertyId, decodedCACK.PresentValue, ) diff --git a/examples/whois-client.go b/examples/whois-client.go index 30dc2ba..88ae4c2 100644 --- a/examples/whois-client.go +++ b/examples/whois-client.go @@ -11,6 +11,7 @@ import ( "github.com/spf13/cobra" "github.com/ulbios/bacnet" + "github.com/ulbios/bacnet/common" "github.com/ulbios/bacnet/services" ) @@ -39,7 +40,7 @@ func whoIsExample(cmd *cobra.Command, args []string) { log.Fatalf("Failed to resolve UDP address: %s", err) } - _, err = net.InterfaceAddrs() + ifaceAddrs, err := net.InterfaceAddrs() if err != nil { log.Fatalf("couldn't get interface information: %v\n", err) } @@ -71,10 +72,10 @@ func whoIsExample(cmd *cobra.Command, args []string) { if err != nil { log.Fatalf("error reading incoming packet: %v\n", err) } - // if !common.IsLocalAddr(ifaceAddrs, remoteAddr) { - // break - // } - // log.Printf("got our own broadcast, back to listening...\n") + if !common.IsLocalAddr(ifaceAddrs, remoteAddr) { + break + } + log.Printf("got our own broadcast, back to listening...\n") break } diff --git a/objects/primitive.go b/objects/primitive.go index f4e8bcc..6eb7e69 100644 --- a/objects/primitive.go +++ b/objects/primitive.go @@ -9,36 +9,6 @@ import ( "github.com/ulbios/bacnet/common" ) -func DecString(rawPayload APDUPayload) (string, error) { - rawObject, ok := rawPayload.(*Object) - if !ok { - return "", errors.Wrap( - common.ErrWrongPayload, - fmt.Sprintf("DecString not ok: %v", rawPayload), - ) - } - - if rawObject.TagNumber != TagCharacterString || rawObject.TagClass { - return "", errors.Wrap( - common.ErrWrongStructure, - fmt.Sprintf("DecString wrong tag number: %v", rawObject.TagNumber), - ) - } - - return string(rawObject.Data), nil -} - -func EncString(value string) *Object { - newObj := Object{} - - newObj.TagNumber = TagCharacterString - newObj.TagClass = false - newObj.Data = []byte(value) - newObj.Length = uint8(len(newObj.Data)) - - return &newObj -} - func DecUnisgnedInteger(rawPayload APDUPayload) (uint32, error) { rawObject, ok := rawPayload.(*Object) if !ok { @@ -71,19 +41,6 @@ func DecUnisgnedInteger(rawPayload APDUPayload) (uint32, error) { fmt.Sprintf("DecUnisgnedInteger not implemented data: %v", rawObject.Data), ) } -func EncUnsignedInteger8(value uint8) *Object { - newObj := Object{} - - data := make([]byte, 1) - data[0] = value - - newObj.TagNumber = TagUnsignedInteger - newObj.TagClass = false - newObj.Data = data - newObj.Length = uint8(len(data)) - - return &newObj -} func EncUnsignedInteger16(value uint16) *Object { newObj := Object{} diff --git a/parsing.go b/parsing.go index 735b483..5014281 100644 --- a/parsing.go +++ b/parsing.go @@ -35,13 +35,12 @@ func Parse(b []byte) (plumbing.BACnet, error) { return nil, errors.Wrap(err, fmt.Sprintf("Parsing BVLC %x", b)) } offset += bvlc.MarshalLen() - log.Printf("BVLC %x\n", b[:offset]) + if err := npdu.UnmarshalBinary(b[offset:]); err != nil { return nil, errors.Wrap(err, fmt.Sprintf("Parsing NPDU %x", b[offset:])) } offset += npdu.MarshalLen() - log.Printf("NPDU %x\n", b[:offset]) - log.Printf("APDU %x\n", b[offset:]) + var c uint16 switch b[offset] >> 4 & 0xFF { case plumbing.UnConfirmedReq: @@ -51,7 +50,7 @@ func Parse(b []byte) (plumbing.BACnet, error) { case plumbing.ComplexAck, plumbing.SimpleAck, plumbing.Error: c = combine(b[offset], 0) // We need to skip the PDU flags and the InvokeID } - fmt.Printf("switch: %x\n", c) + switch c { case combine(plumbing.UnConfirmedReq<<4, services.ServiceUnconfirmedWhoIs): bacnet = services.NewUnconfirmedWhoIs(&bvlc, &npdu) @@ -73,6 +72,7 @@ func Parse(b []byte) (plumbing.BACnet, error) { fmt.Sprintf("Parsing service: %x", c), ) } + if err := bacnet.UnmarshalBinary(b); err != nil { return nil, errors.Wrap( err, diff --git a/plumbing/apdu.go b/plumbing/apdu.go index c97bc15..ff09bcc 100644 --- a/plumbing/apdu.go +++ b/plumbing/apdu.go @@ -30,7 +30,6 @@ func NewAPDU(t, s uint8, objs []objects.APDUPayload) *APDU { // UnmarshalBinary sets the values retrieved from byte sequence in a APDU frame. func (a *APDU) UnmarshalBinary(b []byte) error { - fmt.Println("UnmarshalBinary APDU") if l := len(b); l < a.MarshalLen() { return errors.Wrap( common.ErrTooShortToParse, @@ -42,7 +41,6 @@ func (a *APDU) UnmarshalBinary(b []byte) error { a.Flags = b[0] & 0x7 var offset int = 1 - fmt.Println("Type: ", a.Type) switch a.Type { case UnConfirmedReq: a.Service = b[offset] @@ -101,13 +99,10 @@ func (a *APDU) UnmarshalBinary(b []byte) error { a.Objects = objs } case ComplexAck, SimpleAck, Error: - fmt.Printf("case ACK/Err offset: %d\n", offset) a.InvokeID = b[offset] offset++ - fmt.Printf("InvokeID %x offset %d\n", a.InvokeID, offset) a.Service = b[offset] offset++ - fmt.Printf("Service %x offset %d\n", a.Service, offset) if len(b) > 3 { objs := []objects.APDUPayload{} for { @@ -117,15 +112,8 @@ func (a *APDU) UnmarshalBinary(b []byte) error { Length: b[offset] & 0x7, } - // Handle extended value case - if o.Length == 5 { - offset++ - o.Length = uint8(b[offset]) - } - // Drop tags so that they don't get in the way! if b[offset] == objects.TagOpening || b[offset] == objects.TagClosing { - fmt.Print("tag opening/closing\n") offset++ if offset >= len(b) { break @@ -134,7 +122,6 @@ func (a *APDU) UnmarshalBinary(b []byte) error { } o.Data = b[offset+1 : offset+int(o.Length)+1] - fmt.Printf("APDU object %v\n data %x\n offset %d\n", o, o.Data, offset) objs = append(objs, &o) offset += int(o.Length) + 1 @@ -142,7 +129,6 @@ func (a *APDU) UnmarshalBinary(b []byte) error { break } } - fmt.Println("Objects: ", len(objs)) a.Objects = objs } } diff --git a/services/cack.go b/services/cack.go index 0678372..27bbb84 100644 --- a/services/cack.go +++ b/services/cack.go @@ -20,43 +20,20 @@ type ComplexACKDec struct { ObjectType uint16 InstanceId uint32 PropertyId uint8 - PresentValue interface{} + PresentValue float32 } -func ComplexACKObjects(objectType uint16, instN uint32, propertyId uint8, value interface{}) []objects.APDUPayload { +func ComplexACKObjects(objectType uint16, instN uint32, propertyId uint8, value float32) []objects.APDUPayload { objs := make([]objects.APDUPayload, 5) - fmt.Println("ComplexACKObjects") objs[0] = objects.EncObjectIdentifier(true, 0, objectType, instN) objs[1] = objects.EncPropertyIdentifier(true, 1, propertyId) objs[2] = objects.EncOpeningTag(3) - - switch v := value.(type) { - case int: - objs[3] = objects.EncReal(float32(v)) - case uint8: - objs[3] = objects.EncUnsignedInteger8(v) - case uint16: - objs[3] = objects.EncUnsignedInteger16(v) - case float32: - objs[3] = objects.EncReal(v) - case string: - objs[3] = objects.EncString(v) - default: - panic( - fmt.Sprintf("Unsupported PresentValue type %T", value), - ) - } - + objs[3] = objects.EncReal(value) objs[4] = objects.EncClosingTag(3) - for _, o := range objs { - fmt.Printf("%v\n", o) - } - fmt.Println("ComplexACKObjects end") return objs } func NewComplexACK(bvlc *plumbing.BVLC, npdu *plumbing.NPDU) *ComplexACK { - fmt.Println("NewComplexACK") c := &ComplexACK{ BVLC: bvlc, NPDU: npdu, @@ -65,13 +42,10 @@ func NewComplexACK(bvlc *plumbing.BVLC, npdu *plumbing.NPDU) *ComplexACK { objects.ObjectTypeAnalogOutput, 1, objects.PropertyIdPresentValue, 0)), } c.SetLength() - fmt.Printf("Type: %d, Service: %d\n", c.APDU.Type, c.APDU.Service) - fmt.Println("NewComplexACK end") return c } func (c *ComplexACK) UnmarshalBinary(b []byte) error { - fmt.Printf("unmarshalBinary %x\n", b) if l := len(b); l < c.MarshalLen() { return errors.Wrap( common.ErrTooShortToParse, @@ -96,8 +70,6 @@ func (c *ComplexACK) UnmarshalBinary(b []byte) error { } offset += c.NPDU.MarshalLen() - fmt.Printf("\n\nAPDU binary %x\n", b[offset+11:]) - if err := c.APDU.UnmarshalBinary(b[offset:]); err != nil { return errors.Wrap( common.ErrTooShortToParse, @@ -173,50 +145,27 @@ func (c *ComplexACK) Decode() (ComplexACKDec, error) { } for i, obj := range c.APDU.Objects { - enc_obj, ok := obj.(*objects.Object) - if !ok { - return decCACK, errors.Wrap( - common.ErrInvalidObjectType, - fmt.Sprintf("ComplexACK object at index %d is not Object type", i), - ) - } - fmt.Printf( - "Object i %d tagnum %d tagclass %v data %x\n", - i, enc_obj.TagNumber, enc_obj.TagClass, enc_obj.Data, - ) - if enc_obj.TagClass { - switch enc_obj.TagNumber { - case 0: - objId, err := objects.DecObjectIdentifier(obj) - if err != nil { - return decCACK, errors.Wrap(err, "decode Context object case 0") - } - decCACK.ObjectType = objId.ObjectType - decCACK.InstanceId = objId.InstanceNumber - case 1: - propId, err := objects.DecPropertyIdentifier(obj) - if err != nil { - return decCACK, errors.Wrap(err, "decode Context object case 1") - } - decCACK.PropertyId = propId - } - } else { - switch enc_obj.TagNumber { - case 4: - value, err := objects.DecReal(obj) - if err != nil { - return decCACK, errors.Wrap(err, "decode Application object case 4") - } - decCACK.PresentValue = value - case 7: - value, err := objects.DecString(obj) - if err != nil { - return decCACK, errors.Wrap(err, "decode Application object case 7") - } - fmt.Printf("String value %s\n", value) - decCACK.PresentValue = value - } - } + switch i { + case 0: + objId, err := objects.DecObjectIdentifier(obj) + if err != nil { + return decCACK, err + } + decCACK.ObjectType = objId.ObjectType + decCACK.InstanceId = objId.InstanceNumber + case 1: + propId, err := objects.DecPropertyIdentifier(obj) + if err != nil { + return decCACK, err + } + decCACK.PropertyId = propId + case 2: + value, err := objects.DecReal(obj) + if err != nil { + return decCACK, err + } + decCACK.PresentValue = value + } } return decCACK, nil diff --git a/services/iam.go b/services/iam.go index a0ca6d3..a681530 100644 --- a/services/iam.go +++ b/services/iam.go @@ -30,11 +30,7 @@ func IAmObjects(insNum uint32, acceptedSize uint16, supportedSeg uint8, vendorID objs[0] = objects.EncObjectIdentifier(false, objects.TagBACnetObjectIdentifier, objects.ObjectTypeDevice, 321) objs[1] = objects.EncUnsignedInteger16(acceptedSize) objs[2] = objects.EncEnumerated(supportedSeg) - if vendorID < 256 { - objs[3] = objects.EncUnsignedInteger8(uint8(vendorID)) - } else { - objs[3] = objects.EncUnsignedInteger16(vendorID) - } + objs[3] = objects.EncUnsignedInteger16(vendorID) return objs } From c2fd4ff49538719d38a34acfe1590828600ced6a Mon Sep 17 00:00:00 2001 From: jonalfarlinga Date: Wed, 9 Oct 2024 12:52:16 -0500 Subject: [PATCH 7/8] added state info to error flags --- objects/objects.go | 9 ++++---- objects/oid.go | 16 +++------------ objects/primitive.go | 20 +++++++++--------- objects/priority.go | 7 +++---- objects/property.go | 6 +++--- objects/tags.go | 21 ++++++------------- parsing.go | 3 +-- plumbing/apdu.go | 18 ++++++++-------- plumbing/bvlc.go | 8 +++----- plumbing/npdu.go | 4 ++-- services/cack.go | 35 ++++++++++++------------------- services/err.go | 45 +++++++++++++++++++++++++++++----------- services/iam.go | 28 ++++++++++++------------- services/rp.go | 45 +++++++++++++++++++++++++++++----------- services/sack.go | 36 ++++++++++++++++++++++++-------- services/whois.go | 36 ++++++++++++++++++++++++-------- services/wp.go | 49 +++++++++++++++++++++++++++++++------------- 17 files changed, 227 insertions(+), 159 deletions(-) diff --git a/objects/objects.go b/objects/objects.go index 4ecad04..ebd0589 100644 --- a/objects/objects.go +++ b/objects/objects.go @@ -38,9 +38,10 @@ func (o *Object) UnmarshalBinary(b []byte) error { if l := len(b); l < objLenMin { return errors.Wrap( common.ErrTooShortToParse, - fmt.Sprintf("Unmarshal Object bin length %d, marshal length %d", l, objLenMin), + fmt.Sprintf("failed to unmarshal - binary %x - too short", b), ) } + o.TagNumber = b[0] >> 4 o.TagClass = common.IntToBool(int(b[0]) & 0x8 >> 3) o.Length = b[0] & 0x7 @@ -48,7 +49,7 @@ func (o *Object) UnmarshalBinary(b []byte) error { if l := len(b); l < int(o.Length) { return errors.Wrap( common.ErrTooShortToParse, - fmt.Sprintf("Unmarshal Object bin length %d, marshal length %d", l, o.Length), + fmt.Sprintf("failed to unmarshal object - binary %x - marshal length too short", b), ) } @@ -61,7 +62,7 @@ func (o *Object) UnmarshalBinary(b []byte) error { func (o *Object) MarshalBinary() ([]byte, error) { b := make([]byte, o.MarshalLen()) if err := o.MarshalTo(b); err != nil { - return nil, errors.Wrap(err, "Marshal Object") + return nil, errors.Wrap(err, "failed to marshal object") } return b, nil @@ -72,7 +73,7 @@ func (o *Object) MarshalTo(b []byte) error { if len(b) < o.MarshalLen() { return errors.Wrap( common.ErrTooShortToMarshalBinary, - fmt.Sprintf("Marshal Object bin length %d, marshal length %d", len(b), o.MarshalLen()), + fmt.Sprintf("failed to marshal object - binary %x - marshal length too short", b), ) } b[0] = o.TagNumber<<4 | uint8(common.BoolToInt(o.TagClass))<<3 | o.Length diff --git a/objects/oid.go b/objects/oid.go index a930fbc..9f6bdc4 100644 --- a/objects/oid.go +++ b/objects/oid.go @@ -2,7 +2,6 @@ package objects import ( "encoding/binary" - "fmt" "github.com/pkg/errors" "github.com/ulbios/bacnet/common" @@ -18,26 +17,17 @@ func DecObjectIdentifier(rawPayload APDUPayload) (ObjectIdentifier, error) { rawObject, ok := rawPayload.(*Object) if !ok { - return decObjectId, errors.Wrap( - common.ErrWrongPayload, - fmt.Sprintf("DecObjectIdentifier not ok: %T", rawPayload), - ) + return decObjectId, errors.Wrap(common.ErrWrongPayload, "failed to decode ObjectID") } switch rawObject.TagClass { case true: if rawObject.Length != 4 { - return decObjectId, errors.Wrap( - common.ErrWrongStructure, - fmt.Sprintf("DecObjectIdentifier length: %d, tag class: %v", rawObject.Length, rawObject.TagClass), - ) + return decObjectId, errors.Wrap(common.ErrWrongStructure, "failed to decode ObjectID - wrong binary length") } case false: if rawObject.Length != 4 || rawObject.TagNumber != TagBACnetObjectIdentifier { - return decObjectId, errors.Wrap( - common.ErrWrongStructure, - fmt.Sprintf("DecObjectIdentifier length: %d, tag class: %v", rawObject.Length, rawObject.TagClass), - ) + return decObjectId, errors.Wrap(common.ErrWrongStructure, "failed to decode ObjectID - wrong tag number") } } diff --git a/objects/primitive.go b/objects/primitive.go index 6eb7e69..5268507 100644 --- a/objects/primitive.go +++ b/objects/primitive.go @@ -14,14 +14,14 @@ func DecUnisgnedInteger(rawPayload APDUPayload) (uint32, error) { if !ok { return 0, errors.Wrap( common.ErrWrongPayload, - fmt.Sprintf("DecUnisgnedInteger not ok: %v", rawPayload), + fmt.Sprintf("failed to decode UnsignedInteger - %v", rawPayload), ) } if rawObject.TagNumber != TagUnsignedInteger || rawObject.TagClass { return 0, errors.Wrap( common.ErrWrongStructure, - fmt.Sprintf("DecUnisgnedInteger wrong tag number: %v", rawObject.TagNumber), + fmt.Sprintf("failed to decode UnsignedInteger - wrong tag number - %v", rawObject.TagNumber), ) } @@ -38,7 +38,7 @@ func DecUnisgnedInteger(rawPayload APDUPayload) (uint32, error) { return 0, errors.Wrap( common.ErrNotImplemented, - fmt.Sprintf("DecUnisgnedInteger not implemented data: %v", rawObject.Data), + fmt.Sprintf("failed to decode UnsignedInteger - %v", rawObject.Data), ) } @@ -61,14 +61,14 @@ func DecEnumerated(rawPayload APDUPayload) (uint32, error) { if !ok { return 0, errors.Wrap( common.ErrWrongPayload, - fmt.Sprintf("DecEnumerated not ok %v", rawPayload), + fmt.Sprintf("failed to decode EnumObject - %v", rawPayload), ) } if rawObject.TagNumber != TagEnumerated || rawObject.TagClass { return 0, errors.Wrap( common.ErrWrongStructure, - fmt.Sprintf("DecEnumerated wrong tag number: %v", rawObject.TagNumber), + fmt.Sprintf("failed to decode EnumObject - wrong tag number - %v", rawObject.TagNumber), ) } @@ -85,7 +85,7 @@ func DecEnumerated(rawPayload APDUPayload) (uint32, error) { return 0, errors.Wrap( common.ErrNotImplemented, - fmt.Sprintf("DecEnumerated not implemented data: %v", rawObject.Data), + fmt.Sprintf("failed to decode EnumObject - %v", rawObject.Data), ) } @@ -108,14 +108,14 @@ func DecReal(rawPayload APDUPayload) (float32, error) { if !ok { return 0, errors.Wrap( common.ErrWrongPayload, - fmt.Sprintf("DecReal not ok: %v", rawPayload), + fmt.Sprintf("failed to decode Real - %v", rawPayload), ) } if rawObject.TagNumber != TagReal { return 0, errors.Wrap( common.ErrWrongStructure, - fmt.Sprintf("DecReal bad tag number: %v", rawObject.TagNumber), + fmt.Sprintf("failed to decode real - wrong tag number - %v", rawObject.TagNumber), ) } @@ -141,14 +141,14 @@ func DecNull(rawPayload APDUPayload) (bool, error) { if !ok { return false, errors.Wrap( common.ErrWrongPayload, - fmt.Sprintf("DecNull not ok %v", rawPayload), + fmt.Sprintf("failed to decode Null - %v", rawPayload), ) } if rawObject.TagNumber != TagReal { return false, errors.Wrap( common.ErrWrongStructure, - fmt.Sprintf("DecNull bad tag number %v", rawObject.TagNumber), + fmt.Sprintf("failed to decode Null - wrong tag number - %v", rawObject.TagNumber), ) } diff --git a/objects/priority.go b/objects/priority.go index 4ec7b5c..fda0f73 100644 --- a/objects/priority.go +++ b/objects/priority.go @@ -12,7 +12,7 @@ func DecPriority(rawPayload APDUPayload) (uint8, error) { if !ok { return 0, errors.Wrap( common.ErrWrongPayload, - fmt.Sprintf("DecPriority not ok %v", rawPayload), + fmt.Sprintf("failed to decode Priority Object - %v", rawPayload), ) } @@ -21,14 +21,13 @@ func DecPriority(rawPayload APDUPayload) (uint8, error) { if rawObject.Length != 1 { return 0, errors.Wrap( common.ErrWrongStructure, - fmt.Sprintf("DecPriority length %d tag class %v", rawObject.Length, rawObject.TagClass), - ) + fmt.Sprintf("failed to decode Priority Object - wrong binary length - %x", rawObject.Data),) } case false: if rawObject.Length != 1 || !rawObject.TagClass { return 0, errors.Wrap( common.ErrWrongStructure, - fmt.Sprintf("DecPriority length %d tag class %v", rawObject.Length, rawObject.TagClass), + fmt.Sprintf("failed to decode Priority Object - wrong tag number - %v", rawObject.TagNumber), ) } } diff --git a/objects/property.go b/objects/property.go index 9088456..fd15e60 100644 --- a/objects/property.go +++ b/objects/property.go @@ -12,7 +12,7 @@ func DecPropertyIdentifier(rawPayload APDUPayload) (uint8, error) { if !ok { return 0, errors.Wrap( common.ErrWrongPayload, - fmt.Sprintf("DecPropertyIdentifier not ok %v", rawPayload), + fmt.Sprintf("failed to decode PropertyID - %v", rawPayload), ) } @@ -21,14 +21,14 @@ func DecPropertyIdentifier(rawPayload APDUPayload) (uint8, error) { if rawObject.Length != 1 { return 0, errors.Wrap( common.ErrWrongStructure, - fmt.Sprintf("DecPropertyIdentifier length %d tag class %v", rawObject.Length, rawObject.TagClass), + fmt.Sprintf("failed to decode PropertyID - wrong binary length - %x", rawObject.Data), ) } case false: if rawObject.Length != 1 || !rawObject.TagClass { return 0, errors.Wrap( common.ErrWrongStructure, - fmt.Sprintf("DecPropertyIdentifier length %d tag class %v", rawObject.Length, rawObject.TagClass), + fmt.Sprintf("failed to decode PropertyID - wrong tag number - %v", rawObject.TagNumber), ) } } diff --git a/objects/tags.go b/objects/tags.go index 1437380..aebdf7c 100644 --- a/objects/tags.go +++ b/objects/tags.go @@ -25,7 +25,7 @@ func (n *NamedTag) UnmarshalBinary(b []byte) error { if l := len(b); l < objLenMin { return errors.Wrap( common.ErrTooShortToParse, - fmt.Sprintf("Unmarshal NamedTag bin length %d, min length %d", l, objLenMin), + fmt.Sprintf("failed to unmarshal NamedTag - binary too short - %x", b), ) } n.TagNumber = b[0] >> 4 @@ -35,7 +35,7 @@ func (n *NamedTag) UnmarshalBinary(b []byte) error { if l := len(b); l < 1 { return errors.Wrap( common.ErrTooShortToParse, - fmt.Sprintf("Unmarshal NamedTag bin length %d", l), + fmt.Sprintf("failed to unmarshal NamedTag - missing data - %v", n), ) } @@ -45,7 +45,7 @@ func (n *NamedTag) UnmarshalBinary(b []byte) error { func (n *NamedTag) MarshalBinary() ([]byte, error) { b := make([]byte, n.MarshalLen()) if err := n.MarshalTo(b); err != nil { - return nil, errors.Wrap(err, "unable to marshal NamedTag") + return nil, errors.Wrap(err, "failed to marshal binary") } return b, nil @@ -53,10 +53,7 @@ func (n *NamedTag) MarshalBinary() ([]byte, error) { func (n *NamedTag) MarshalTo(b []byte) error { if len(b) < n.MarshalLen() { - return errors.Wrap( - common.ErrTooShortToMarshalBinary, - fmt.Sprintf("marshall NamedTag length %d is less than %d", len(b), n.MarshalLen()), - ) + return errors.Wrap(common.ErrTooShortToMarshalBinary, "failed to marshall NamedTag - marshal length too short") } b[0] = n.TagNumber<<4 | uint8(common.BoolToInt(n.TagClass))<<3 | n.Name @@ -70,10 +67,7 @@ func (n *NamedTag) MarshalLen() int { func DecOpeningTab(rawPayload APDUPayload) (bool, error) { rawTag, ok := rawPayload.(*NamedTag) if !ok { - return false, errors.Wrap( - common.ErrWrongPayload, - fmt.Sprintf("DecOpeningTab not ok %T", rawPayload), - ) + return false, errors.Wrap(common.ErrWrongPayload, "failed to decode OpeningTab") } return rawTag.Name == 0x6 && rawTag.TagClass, nil } @@ -91,10 +85,7 @@ func EncOpeningTag(tagN uint8) *NamedTag { func DecClosingTab(rawPayload APDUPayload) (bool, error) { rawTag, ok := rawPayload.(*NamedTag) if !ok { - return false, errors.Wrap( - common.ErrWrongPayload, - fmt.Sprintf("DecClosingTab not ok %T", rawPayload), - ) + return false, errors.Wrap(common.ErrWrongPayload, "failed to decode ClosingTab") } return rawTag.Name == 0x7 && rawTag.TagClass, nil } diff --git a/parsing.go b/parsing.go index 5014281..ada6cab 100644 --- a/parsing.go +++ b/parsing.go @@ -2,7 +2,6 @@ package bacnet import ( "fmt" - "log" "github.com/pkg/errors" "github.com/ulbios/bacnet/common" @@ -72,7 +71,7 @@ func Parse(b []byte) (plumbing.BACnet, error) { fmt.Sprintf("Parsing service: %x", c), ) } - + if err := bacnet.UnmarshalBinary(b); err != nil { return nil, errors.Wrap( err, diff --git a/plumbing/apdu.go b/plumbing/apdu.go index ff09bcc..add4a94 100644 --- a/plumbing/apdu.go +++ b/plumbing/apdu.go @@ -33,7 +33,7 @@ func (a *APDU) UnmarshalBinary(b []byte) error { if l := len(b); l < a.MarshalLen() { return errors.Wrap( common.ErrTooShortToParse, - fmt.Sprintf("Unmarshal APDU bin length %d, marshal length %d", l, a.MarshalLen()), + fmt.Sprintf("failed to unmarshal APDU %v - marshal length too short", a.Type), ) } @@ -114,7 +114,7 @@ func (a *APDU) UnmarshalBinary(b []byte) error { // Drop tags so that they don't get in the way! if b[offset] == objects.TagOpening || b[offset] == objects.TagClosing { - offset++ + offset++ if offset >= len(b) { break } @@ -141,7 +141,7 @@ func (a *APDU) MarshalTo(b []byte) error { if len(b) < a.MarshalLen() { return errors.Wrap( common.ErrTooShortToMarshalBinary, - fmt.Sprintf("Marshal APDU bin length %d, marshal length %d", len(b), a.MarshalLen()), + fmt.Sprintf("failed to marshal APDU %v - marshal length too short", a.Type), ) } @@ -157,7 +157,7 @@ func (a *APDU) MarshalTo(b []byte) error { for _, o := range a.Objects { ob, err := o.MarshalBinary() if err != nil { - return errors.Wrap(err, "Marshal APDU") + return errors.Wrap(err, "failed to marshal UnconfirmedReq") } copy(b[offset:offset+o.MarshalLen()], ob) @@ -166,7 +166,7 @@ func (a *APDU) MarshalTo(b []byte) error { if offset > a.MarshalLen() { return errors.Wrap( common.ErrTooShortToMarshalBinary, - fmt.Sprintf("Marshal APDU bin length %d, marshal length %d", len(b), a.MarshalLen()), + fmt.Sprintf("failed to marshal UnconfirmedReq %v - marshal length too short", a.Type), ) } } @@ -180,7 +180,7 @@ func (a *APDU) MarshalTo(b []byte) error { for _, o := range a.Objects { ob, err := o.MarshalBinary() if err != nil { - return errors.Wrap(err, "Marshal APDU") + return errors.Wrap(err, "failed to marshal CACK/SACK/ERROR") } copy(b[offset:offset+o.MarshalLen()], ob) @@ -189,7 +189,7 @@ func (a *APDU) MarshalTo(b []byte) error { if offset > a.MarshalLen() { return errors.Wrap( common.ErrTooShortToMarshalBinary, - fmt.Sprintf("Marshal APDU bin length %d, marshal length %d", len(b), a.MarshalLen()), + fmt.Sprintf("failed to marshal CACK/SACK/ERROR %x - binary overflow", b), ) } } @@ -205,7 +205,7 @@ func (a *APDU) MarshalTo(b []byte) error { for _, o := range a.Objects { ob, err := o.MarshalBinary() if err != nil { - return errors.Wrap(err, "Marshal APDU") + return errors.Wrap(err, "failed to marshal ConfirmedReq") } copy(b[offset:offset+o.MarshalLen()], ob) @@ -214,7 +214,7 @@ func (a *APDU) MarshalTo(b []byte) error { if offset > a.MarshalLen() { return errors.Wrap( common.ErrTooShortToMarshalBinary, - fmt.Sprintf("Marshal APDU bin length %d, marshal length %d", len(b), a.MarshalLen()), + fmt.Sprintf("failed to marshal ConfirmedReq %v - binary overflow", a.Type), ) } } diff --git a/plumbing/bvlc.go b/plumbing/bvlc.go index 2a5b70d..f537d38 100644 --- a/plumbing/bvlc.go +++ b/plumbing/bvlc.go @@ -38,9 +38,7 @@ func (bvlc *BVLC) UnmarshalBinary(b []byte) error { if l := len(b); l < bvlc.MarshalLen() { return errors.Wrap( common.ErrTooShortToParse, - fmt.Sprintf( - "Unmarshal BVLC bin length %d, marshal length %d", - l, bvlc.MarshalLen()), + fmt.Sprintf("failed to unmarshal BVLC %v - binary too short", bvlc.Function), ) } bvlc.Type = b[0] @@ -54,7 +52,7 @@ func (bvlc *BVLC) UnmarshalBinary(b []byte) error { func (bvlc *BVLC) MarshalBinary() ([]byte, error) { b := make([]byte, bvlc.MarshalLen()) if err := bvlc.MarshalTo(b); err != nil { - return nil, errors.Wrap(err, "unable to marshal BVLC") + return nil, errors.Wrap(err, "failed to marshal binary") } return b, nil @@ -72,7 +70,7 @@ func (bvlc *BVLC) MarshalTo(b []byte) error { if len(b) < bvlc.MarshalLen() { return errors.Wrap( common.ErrTooShortToMarshalBinary, - fmt.Sprintf("Marshal BVLC bin length %d, marshal length %d", len(b), bvlc.MarshalLen()), + fmt.Sprintf("failed to marshal BVLC %v - marshal length too short", bvlc.Function), ) } b[0] = byte(bvlc.Type) diff --git a/plumbing/npdu.go b/plumbing/npdu.go index 307e9b1..7059c10 100644 --- a/plumbing/npdu.go +++ b/plumbing/npdu.go @@ -39,7 +39,7 @@ func (n *NPDU) UnmarshalBinary(b []byte) error { if l := len(b); l < n.MarshalLen() { return errors.Wrap( common.ErrTooShortToParse, - fmt.Sprintf("Unmarshal NPDU bin length %d, marshal length %d", l, n.MarshalLen()), + fmt.Sprintf("failed to unmarshal NPDU %v - marshal length too short", n), ) } n.Version = b[0] @@ -58,7 +58,7 @@ func (n *NPDU) MarshalTo(b []byte) error { if len(b) < n.MarshalLen() { return errors.Wrap( common.ErrTooShortToMarshalBinary, - fmt.Sprintf("Marshal NPDU bin length %d, marshal length %d", len(b), n.MarshalLen()), + fmt.Sprintf("failed to marshall NPDU %v - marshal length too short", n), ) } b[0] = n.Version diff --git a/services/cack.go b/services/cack.go index 27bbb84..fc8e29c 100644 --- a/services/cack.go +++ b/services/cack.go @@ -49,7 +49,7 @@ func (c *ComplexACK) UnmarshalBinary(b []byte) error { if l := len(b); l < c.MarshalLen() { return errors.Wrap( common.ErrTooShortToParse, - fmt.Sprintf("unmarshal ComplexACK bin length %d, marshal length %d", l, c.MarshalLen()), + fmt.Sprintf("failed to unmarshal CACK %v - marshal length too short", c), ) } @@ -57,7 +57,7 @@ func (c *ComplexACK) UnmarshalBinary(b []byte) error { if err := c.BVLC.UnmarshalBinary(b[offset:]); err != nil { return errors.Wrap( common.ErrTooShortToParse, - fmt.Sprintf("unmarshal BVLC %x", b[offset:]), + fmt.Sprintf("unmarshalling CACK %v", c), ) } offset += c.BVLC.MarshalLen() @@ -65,7 +65,7 @@ func (c *ComplexACK) UnmarshalBinary(b []byte) error { if err := c.NPDU.UnmarshalBinary(b[offset:]); err != nil { return errors.Wrap( common.ErrTooShortToParse, - fmt.Sprintf("unmarshal NPDU %x", b[offset:]), + fmt.Sprintf("unmarshalling CACK %v", c), ) } offset += c.NPDU.MarshalLen() @@ -73,7 +73,7 @@ func (c *ComplexACK) UnmarshalBinary(b []byte) error { if err := c.APDU.UnmarshalBinary(b[offset:]); err != nil { return errors.Wrap( common.ErrTooShortToParse, - fmt.Sprintf("unmarshal APDU %x", b[offset:]), + fmt.Sprintf("unmarshalling CACK %v", c), ) } @@ -83,7 +83,7 @@ func (c *ComplexACK) UnmarshalBinary(b []byte) error { func (c *ComplexACK) MarshalBinary() ([]byte, error) { b := make([]byte, c.MarshalLen()) if err := c.MarshalTo(b); err != nil { - return nil, errors.Wrap(err, "unable to marshal ComplexACK") + return nil, errors.Wrap(err, "failed to marshal binary - marshal length too short") } return b, nil } @@ -92,31 +92,22 @@ func (c *ComplexACK) MarshalTo(b []byte) error { if len(b) < c.MarshalLen() { return errors.Wrap( common.ErrTooShortToMarshalBinary, - fmt.Sprintf("marshal ComplexACK bin length %d, marshal length %d", len(b), c.MarshalLen()), + fmt.Sprintf("failed to marshal CACK %x - marshal length too short", b), ) } var offset = 0 if err := c.BVLC.MarshalTo(b[offset:]); err != nil { - return errors.Wrap( - err, - fmt.Sprintf("marshal BVLC %x", b[offset:]), - ) + return errors.Wrap(err, "marshalling CACK") } offset += c.BVLC.MarshalLen() if err := c.NPDU.MarshalTo(b[offset:]); err != nil { - return errors.Wrap( - err, - fmt.Sprintf("marshal NPDU %x", b[offset:]), - ) + return errors.Wrap(err, "marshalling CACK") } offset += c.NPDU.MarshalLen() if err := c.APDU.MarshalTo(b[offset:]); err != nil { - return errors.Wrap( - err, - fmt.Sprintf("marshal APDU %x", b[offset:]), - ) + return errors.Wrap(err, "marshalling CACK") } return nil @@ -140,7 +131,7 @@ func (c *ComplexACK) Decode() (ComplexACKDec, error) { if len(c.APDU.Objects) != 3 { return decCACK, errors.Wrap( common.ErrWrongObjectCount, - fmt.Sprintf("complexACK object count %d", len(c.APDU.Objects)), + fmt.Sprintf("failed to decode CACK - objects count: %d", len(c.APDU.Objects)), ) } @@ -149,20 +140,20 @@ func (c *ComplexACK) Decode() (ComplexACKDec, error) { case 0: objId, err := objects.DecObjectIdentifier(obj) if err != nil { - return decCACK, err + return decCACK, errors.Wrap(err, "decoding CACK") } decCACK.ObjectType = objId.ObjectType decCACK.InstanceId = objId.InstanceNumber case 1: propId, err := objects.DecPropertyIdentifier(obj) if err != nil { - return decCACK, err + return decCACK, errors.Wrap(err, "decoding CACK") } decCACK.PropertyId = propId case 2: value, err := objects.DecReal(obj) if err != nil { - return decCACK, err + return decCACK, errors.Wrap(err, "decoding CACK") } decCACK.PresentValue = value } diff --git a/services/err.go b/services/err.go index f5d4383..959c4db 100644 --- a/services/err.go +++ b/services/err.go @@ -1,6 +1,9 @@ package services import ( + "fmt" + + "github.com/pkg/errors" "github.com/ulbios/bacnet/common" "github.com/ulbios/bacnet/objects" "github.com/ulbios/bacnet/plumbing" @@ -44,22 +47,34 @@ func NewError(bvlc *plumbing.BVLC, npdu *plumbing.NPDU) *Error { // UnmarshalBinary sets the values retrieved from byte sequence in a UnconfirmedIAm frame. func (e *Error) UnmarshalBinary(b []byte) error { if l := len(b); l < e.MarshalLen() { - return common.ErrTooShortToParse + return errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf("failed to unmarshal Error %v - marshal length too short", e), + ) } var offset int = 0 if err := e.BVLC.UnmarshalBinary(b[offset:]); err != nil { - return common.ErrTooShortToParse + return errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf("unmarshalling Error %v", e), + ) } offset += e.BVLC.MarshalLen() if err := e.NPDU.UnmarshalBinary(b[offset:]); err != nil { - return common.ErrTooShortToParse + return errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf("unmarshalling Error %v", e), + ) } offset += e.NPDU.MarshalLen() if err := e.APDU.UnmarshalBinary(b[offset:]); err != nil { - return common.ErrTooShortToParse + return errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf("unmarshalling Error %v", e), + ) } return nil @@ -69,7 +84,7 @@ func (e *Error) UnmarshalBinary(b []byte) error { func (e *Error) MarshalBinary() ([]byte, error) { b := make([]byte, e.MarshalLen()) if err := e.MarshalTo(b); err != nil { - return nil, err + return nil, errors.Wrap(err, "failed to marshal binary - marshal length too short") } return b, nil } @@ -77,21 +92,24 @@ func (e *Error) MarshalBinary() ([]byte, error) { // MarshalTo puts the byte sequence in the byte array given as b. func (e *Error) MarshalTo(b []byte) error { if len(b) < e.MarshalLen() { - return common.ErrTooShortToMarshalBinary + return errors.Wrap( + common.ErrTooShortToMarshalBinary, + fmt.Sprintf("failed to marshal Error %x - marshal length too short", b), + ) } var offset = 0 if err := e.BVLC.MarshalTo(b[offset:]); err != nil { - return err + return errors.Wrap(err, "marshalling Error") } offset += e.BVLC.MarshalLen() if err := e.NPDU.MarshalTo(b[offset:]); err != nil { - return err + return errors.Wrap(err, "marshalling Error") } offset += e.NPDU.MarshalLen() if err := e.APDU.MarshalTo(b[offset:]); err != nil { - return err + return errors.Wrap(err, "marshalling Error") } return nil @@ -115,7 +133,10 @@ func (e *Error) Decode() (ErrorDec, error) { decErr := ErrorDec{} if len(e.APDU.Objects) != 2 { - return decErr, common.ErrWrongObjectCount + return decErr, errors.Wrap( + common.ErrWrongObjectCount, + fmt.Sprintf("failed to decode Error - object count: %d", len(e.APDU.Objects)), + ) } for i, obj := range e.APDU.Objects { @@ -123,13 +144,13 @@ func (e *Error) Decode() (ErrorDec, error) { case 0: errClass, err := objects.DecEnumerated(obj) if err != nil { - return decErr, err + return decErr, errors.Wrap(err, "failed to decode Enumerated Object") } decErr.ErrorClass = uint8(errClass) case 1: errCode, err := objects.DecEnumerated(obj) if err != nil { - return decErr, err + return decErr, errors.Wrap(err, "failed to decode Enumerated Object") } decErr.ErrorCode = uint8(errCode) } diff --git a/services/iam.go b/services/iam.go index a681530..1f2d148 100644 --- a/services/iam.go +++ b/services/iam.go @@ -53,7 +53,7 @@ func (u *UnconfirmedIAm) UnmarshalBinary(b []byte) error { if l := len(b); l < u.MarshalLen() { return errors.Wrap( common.ErrTooShortToParse, - fmt.Sprintf("Unmarshal UnconfirmedIAm bin length %d, marshal length %d", l, u.MarshalLen()), + fmt.Sprintf("failed to unmarshal UnconfirmedIAm %x - marshal length too short", b), ) } @@ -61,7 +61,7 @@ func (u *UnconfirmedIAm) UnmarshalBinary(b []byte) error { if err := u.BVLC.UnmarshalBinary(b[offset:]); err != nil { return errors.Wrap( common.ErrTooShortToParse, - fmt.Sprintf("Unmarshal UIAm BVLC %x", b[offset:]), + fmt.Sprintf("unmarshalling UnconfirmedIAm %v", u), ) } offset += u.BVLC.MarshalLen() @@ -69,7 +69,7 @@ func (u *UnconfirmedIAm) UnmarshalBinary(b []byte) error { if err := u.NPDU.UnmarshalBinary(b[offset:]); err != nil { return errors.Wrap( common.ErrTooShortToParse, - fmt.Sprintf("Unmarshal UIAm NPDU %x", b[offset:]), + fmt.Sprintf("unmarshalling UnconfirmedIAm %v", u), ) } offset += u.NPDU.MarshalLen() @@ -77,7 +77,7 @@ func (u *UnconfirmedIAm) UnmarshalBinary(b []byte) error { if err := u.APDU.UnmarshalBinary(b[offset:]); err != nil { return errors.Wrap( common.ErrTooShortToParse, - fmt.Sprintf("Unmarshal UIAm APDU %x", b[offset:]), + fmt.Sprintf("unmarshalling UnconfirmedIAm %v", u), ) } @@ -88,7 +88,7 @@ func (u *UnconfirmedIAm) UnmarshalBinary(b []byte) error { func (u *UnconfirmedIAm) MarshalBinary() ([]byte, error) { b := make([]byte, u.MarshalLen()) if err := u.MarshalTo(b); err != nil { - return nil, errors.Wrap(err, "Marshal UnconfirmedIAm") + return nil, errors.Wrap(err, "failed to marshal binary - marshal length too short") } return b, nil } @@ -98,22 +98,22 @@ func (u *UnconfirmedIAm) MarshalTo(b []byte) error { if len(b) < u.MarshalLen() { return errors.Wrap( common.ErrTooShortToMarshalBinary, - fmt.Sprintf("Marshal UnconfirmedIAm bin lenght %d, marshal length %d", len(b), u.MarshalLen()), + fmt.Sprintf("failed to marshal UnconfirmedIAm %x - marshal length too short", b), ) } var offset = 0 if err := u.BVLC.MarshalTo(b[offset:]); err != nil { - return errors.Wrap(err, "Marshal UnconfirmedIAm") + return errors.Wrap(err, "marshalling UnconfirmedIAm") } offset += u.BVLC.MarshalLen() if err := u.NPDU.MarshalTo(b[offset:]); err != nil { - return errors.Wrap(err, "Marshal UnconfirmedIAm") + return errors.Wrap(err, "marshalling UnconfirmedIAm") } offset += u.NPDU.MarshalLen() if err := u.APDU.MarshalTo(b[offset:]); err != nil { - return errors.Wrap(err, "Marshal UnconfirmedIAm") + return errors.Wrap(err, "marshalling UnconfirmedIAm") } return nil @@ -139,7 +139,7 @@ func (u *UnconfirmedIAm) Decode() (UnconfirmedIAmDec, error) { if len(u.APDU.Objects) != 4 { return decIAm, errors.Wrap( common.ErrWrongObjectCount, - fmt.Sprintf("Decode UnconfirmedIAm object count %d", len(u.APDU.Objects)), + fmt.Sprintf("failed to decode UnconfirmedIAm %d - wrong object count", len(u.APDU.Objects)), ) } @@ -148,25 +148,25 @@ func (u *UnconfirmedIAm) Decode() (UnconfirmedIAmDec, error) { case 0: objId, err := objects.DecObjectIdentifier(obj) if err != nil { - return decIAm, errors.Wrap(err, "Decode UnconfirmedIAm ObjectIdentifier") + return decIAm, errors.Wrap(err, "decoding UnconfirmedIAm") } decIAm.DeviceId = objId.InstanceNumber case 1: maxLen, err := objects.DecUnisgnedInteger(obj) if err != nil { - return decIAm, errors.Wrap(err, "Decode UnconfirmedIAm UnsignedInteger") + return decIAm, errors.Wrap(err, "decoding UnconfirmedIAm") } decIAm.MaxAPDULength = uint16(maxLen) case 2: segSupport, err := objects.DecEnumerated(obj) if err != nil { - return decIAm, errors.Wrap(err, "Decode UnconfirmedIAm Enumerated") + return decIAm, errors.Wrap(err, "decoding UnconfirmedIAm") } decIAm.SegmentationSupported = uint8(segSupport) case 3: vendorId, err := objects.DecUnisgnedInteger(obj) if err != nil { - return decIAm, errors.Wrap(err, "Decode UnconfirmedIAm UnsignedInteger") + return decIAm, errors.Wrap(err, "decoding UnconfirmedIAm") } decIAm.VendorId = uint16(vendorId) } diff --git a/services/rp.go b/services/rp.go index b6eb281..b348b63 100644 --- a/services/rp.go +++ b/services/rp.go @@ -1,6 +1,9 @@ package services import ( + "fmt" + + "github.com/pkg/errors" "github.com/ulbios/bacnet/common" "github.com/ulbios/bacnet/objects" "github.com/ulbios/bacnet/plumbing" @@ -43,22 +46,34 @@ func NewConfirmedReadProperty(bvlc *plumbing.BVLC, npdu *plumbing.NPDU) *Confirm func (c *ConfirmedReadProperty) UnmarshalBinary(b []byte) error { if l := len(b); l < c.MarshalLen() { - return common.ErrTooShortToParse + return errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf("failed to unmarshal ConfirmedRP %v - marshal length too short", c), + ) } var offset int = 0 if err := c.BVLC.UnmarshalBinary(b[offset:]); err != nil { - return common.ErrTooShortToParse + return errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf("unmarshalling ConfirmedRP %v", c), + ) } offset += c.BVLC.MarshalLen() if err := c.NPDU.UnmarshalBinary(b[offset:]); err != nil { - return common.ErrTooShortToParse + return errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf("unmarshalling ConfirmedRP %v", c), + ) } offset += c.NPDU.MarshalLen() if err := c.APDU.UnmarshalBinary(b[offset:]); err != nil { - return common.ErrTooShortToParse + return errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf("unmarshalling ConfirmedRP %v", c), + ) } return nil @@ -67,28 +82,31 @@ func (c *ConfirmedReadProperty) UnmarshalBinary(b []byte) error { func (c *ConfirmedReadProperty) MarshalBinary() ([]byte, error) { b := make([]byte, c.MarshalLen()) if err := c.MarshalTo(b); err != nil { - return nil, err + return nil, errors.Wrap(err, "failed to marshal binary - marshal length too short") } return b, nil } func (c *ConfirmedReadProperty) MarshalTo(b []byte) error { if len(b) < c.MarshalLen() { - return common.ErrTooShortToMarshalBinary + return errors.Wrap( + common.ErrTooShortToMarshalBinary, + fmt.Sprintf("failed to marshal ConfirmedRP %x - marshal length too short", b), + ) } var offset = 0 if err := c.BVLC.MarshalTo(b[offset:]); err != nil { - return err + return errors.Wrap(err, "failed to marshal ConfirmedRP") } offset += c.BVLC.MarshalLen() if err := c.NPDU.MarshalTo(b[offset:]); err != nil { - return err + return errors.Wrap(err, "failed to marshal ConfirmedRP") } offset += c.NPDU.MarshalLen() if err := c.APDU.MarshalTo(b[offset:]); err != nil { - return err + return errors.Wrap(err, "failed to marshal ConfirmedRP") } return nil @@ -110,7 +128,10 @@ func (c *ConfirmedReadProperty) Decode() (ConfirmedReadPropertyDec, error) { decCRP := ConfirmedReadPropertyDec{} if len(c.APDU.Objects) != 2 { - return decCRP, common.ErrWrongObjectCount + return decCRP, errors.Wrap( + common.ErrWrongObjectCount, + fmt.Sprintf("failed to decode ConfirmedRP - object count %d", len(c.APDU.Objects)), + ) } for i, obj := range c.APDU.Objects { @@ -118,14 +139,14 @@ func (c *ConfirmedReadProperty) Decode() (ConfirmedReadPropertyDec, error) { case 0: objId, err := objects.DecObjectIdentifier(obj) if err != nil { - return decCRP, err + return decCRP, errors.Wrap(err, "decoding ConfirmedRP") } decCRP.ObjectType = objId.ObjectType decCRP.InstanceId = objId.InstanceNumber case 1: propId, err := objects.DecPropertyIdentifier(obj) if err != nil { - return decCRP, err + return decCRP, errors.Wrap(err, "decoding ConfirmedRP") } decCRP.PropertyId = propId } diff --git a/services/sack.go b/services/sack.go index 28160c2..79d2f26 100644 --- a/services/sack.go +++ b/services/sack.go @@ -1,6 +1,9 @@ package services import ( + "fmt" + + "github.com/pkg/errors" "github.com/ulbios/bacnet/common" "github.com/ulbios/bacnet/plumbing" ) @@ -26,22 +29,34 @@ func NewSimpleACK(bvlc *plumbing.BVLC, npdu *plumbing.NPDU) *SimpleACK { func (s *SimpleACK) UnmarshalBinary(b []byte) error { if l := len(b); l < s.MarshalLen() { - return common.ErrTooShortToParse + return errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf("failed to unmarshal SACK %v - marshal length too short", s), + ) } var offset int = 0 if err := s.BVLC.UnmarshalBinary(b[offset:]); err != nil { - return common.ErrTooShortToParse + return errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf("unmarshalling SACK %v", s), + ) } offset += s.BVLC.MarshalLen() if err := s.NPDU.UnmarshalBinary(b[offset:]); err != nil { - return common.ErrTooShortToParse + return errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf("unmarshalling SACK %v", s), + ) } offset += s.NPDU.MarshalLen() if err := s.APDU.UnmarshalBinary(b[offset:]); err != nil { - return common.ErrTooShortToParse + return errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf("unmarshalling SACK %v", s), + ) } return nil @@ -50,28 +65,31 @@ func (s *SimpleACK) UnmarshalBinary(b []byte) error { func (s *SimpleACK) MarshalBinary() ([]byte, error) { b := make([]byte, s.MarshalLen()) if err := s.MarshalTo(b); err != nil { - return nil, err + return nil, errors.Wrap(err, "failed to marshal binary - marshal length too short") } return b, nil } func (s *SimpleACK) MarshalTo(b []byte) error { if len(b) < s.MarshalLen() { - return common.ErrTooShortToMarshalBinary + return errors.Wrap( + common.ErrTooShortToMarshalBinary, + fmt.Sprintf("failed to marshal SACK %x - marshal length too short", b), + ) } var offset = 0 if err := s.BVLC.MarshalTo(b[offset:]); err != nil { - return err + return errors.Wrap(err, "marshalling SACK") } offset += s.BVLC.MarshalLen() if err := s.NPDU.MarshalTo(b[offset:]); err != nil { - return err + return errors.Wrap(err, "marshalling SACK") } offset += s.NPDU.MarshalLen() if err := s.APDU.MarshalTo(b[offset:]); err != nil { - return err + return errors.Wrap(err, "marshalling SACK") } return nil diff --git a/services/whois.go b/services/whois.go index f70988b..8b69b18 100644 --- a/services/whois.go +++ b/services/whois.go @@ -1,6 +1,9 @@ package services import ( + "fmt" + + "github.com/pkg/errors" "github.com/ulbios/bacnet/common" "github.com/ulbios/bacnet/plumbing" ) @@ -26,22 +29,34 @@ func NewUnconfirmedWhoIs(bvlc *plumbing.BVLC, npdu *plumbing.NPDU) *UnconfirmedW // UnmarshalBinary sets the values retrieved from byte sequence in a UnconfirmedWhoIs frame. func (u *UnconfirmedWhoIs) UnmarshalBinary(b []byte) error { if l := len(b); l < u.MarshalLen() { - return common.ErrTooShortToParse + return errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf("failed to unmarshal UnconfirmedWhoIs %v - marshal length too short", u), + ) } var offset int = 0 if err := u.BVLC.UnmarshalBinary(b[offset:]); err != nil { - return common.ErrTooShortToParse + return errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf("unmarshalling UnconfirmedWhoIs %v", u), + ) } offset += u.BVLC.MarshalLen() if err := u.NPDU.UnmarshalBinary(b[offset:]); err != nil { - return common.ErrTooShortToParse + return errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf("unmarshalling UnconfirmedWhoIs %v", u), + ) } offset += u.NPDU.MarshalLen() if err := u.APDU.UnmarshalBinary(b[offset:]); err != nil { - return common.ErrTooShortToParse + return errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf("unmarshalling UnconfirmedWhoIs %v", u), + ) } return nil @@ -51,7 +66,7 @@ func (u *UnconfirmedWhoIs) UnmarshalBinary(b []byte) error { func (u *UnconfirmedWhoIs) MarshalBinary() ([]byte, error) { b := make([]byte, u.MarshalLen()) if err := u.MarshalTo(b); err != nil { - return nil, err + return nil, errors.Wrap(err, "failed to marshal binary - marshal length too short") } return b, nil } @@ -59,21 +74,24 @@ func (u *UnconfirmedWhoIs) MarshalBinary() ([]byte, error) { // MarshalTo puts the byte sequence in the byte array given as b. func (u *UnconfirmedWhoIs) MarshalTo(b []byte) error { if len(b) < u.MarshalLen() { - return common.ErrTooShortToMarshalBinary + return errors.Wrap( + common.ErrTooShortToMarshalBinary, + fmt.Sprintf("failed to marshal UnconfirmedWhoIs %x - marshal length too short", b), + ) } var offset = 0 if err := u.BVLC.MarshalTo(b[offset:]); err != nil { - return err + return errors.Wrap(err, "marshalling UnconfirmedWhoIs") } offset += u.BVLC.MarshalLen() if err := u.NPDU.MarshalTo(b[offset:]); err != nil { - return err + return errors.Wrap(err, "marshalling UnconfirmedWhoIs") } offset += u.NPDU.MarshalLen() if err := u.APDU.MarshalTo(b[offset:]); err != nil { - return err + return errors.Wrap(err, "marshalling UnconfirmedWhoIs") } return nil diff --git a/services/wp.go b/services/wp.go index 33a6c37..022fef6 100644 --- a/services/wp.go +++ b/services/wp.go @@ -1,6 +1,9 @@ package services import ( + "fmt" + + "github.com/pkg/errors" "github.com/ulbios/bacnet/common" "github.com/ulbios/bacnet/objects" "github.com/ulbios/bacnet/plumbing" @@ -48,22 +51,34 @@ func NewConfirmedWriteProperty(bvlc *plumbing.BVLC, npdu *plumbing.NPDU) *Confir func (c *ConfirmedWriteProperty) UnmarshalBinary(b []byte) error { if l := len(b); l < c.MarshalLen() { - return common.ErrTooShortToParse + return errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf("failed to unmarshal ConfirmedWP %v - marshal length too short", c), + ) } var offset int = 0 if err := c.BVLC.UnmarshalBinary(b[offset:]); err != nil { - return common.ErrTooShortToParse + return errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf("unmarshalling ConfirmedWP %v", c), + ) } offset += c.BVLC.MarshalLen() if err := c.NPDU.UnmarshalBinary(b[offset:]); err != nil { - return common.ErrTooShortToParse + return errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf("unmarshalling ConfirmedWP %v", c), + ) } offset += c.NPDU.MarshalLen() if err := c.APDU.UnmarshalBinary(b[offset:]); err != nil { - return common.ErrTooShortToParse + return errors.Wrap( + common.ErrTooShortToParse, + fmt.Sprintf("unmarshalling ConfirmedWP %v", c), + ) } return nil @@ -72,28 +87,31 @@ func (c *ConfirmedWriteProperty) UnmarshalBinary(b []byte) error { func (c *ConfirmedWriteProperty) MarshalBinary() ([]byte, error) { b := make([]byte, c.MarshalLen()) if err := c.MarshalTo(b); err != nil { - return nil, err + return nil, errors.Wrap(err, "failed to marshal binary - marshal length too short") } return b, nil } func (c *ConfirmedWriteProperty) MarshalTo(b []byte) error { if len(b) < c.MarshalLen() { - return common.ErrTooShortToMarshalBinary + return errors.Wrap( + common.ErrTooShortToMarshalBinary, + fmt.Sprintf("failed to marshal ConfirmedWP %x - marshal length too short", b), + ) } var offset = 0 if err := c.BVLC.MarshalTo(b[offset:]); err != nil { - return err + return errors.Wrap(err, "failed to marshal ConfirmedWP") } offset += c.BVLC.MarshalLen() if err := c.NPDU.MarshalTo(b[offset:]); err != nil { - return err + return errors.Wrap(err, "failed to marshal ConfirmedWP") } offset += c.NPDU.MarshalLen() if err := c.APDU.MarshalTo(b[offset:]); err != nil { - return err + return errors.Wrap(err, "failed to marshal ConfirmedWP") } return nil @@ -115,7 +133,10 @@ func (c *ConfirmedWriteProperty) Decode() (ConfirmedWritePropertyDec, error) { decCWP := ConfirmedWritePropertyDec{} if len(c.APDU.Objects) != 5 { - return decCWP, common.ErrWrongObjectCount + return decCWP, errors.Wrap( + common.ErrWrongObjectCount, + fmt.Sprintf("failed to decode ConfirmedWP - object count %d", len(c.APDU.Objects)), + ) } for i, obj := range c.APDU.Objects { @@ -123,26 +144,26 @@ func (c *ConfirmedWriteProperty) Decode() (ConfirmedWritePropertyDec, error) { case 0: objId, err := objects.DecObjectIdentifier(obj) if err != nil { - return decCWP, err + return decCWP, errors.Wrap(err, "decoding ConfirmedWP") } decCWP.ObjectType = objId.ObjectType decCWP.InstanceId = objId.InstanceNumber case 1: propId, err := objects.DecPropertyIdentifier(obj) if err != nil { - return decCWP, err + return decCWP, errors.Wrap(err, "decoding ConfirmedWP") } decCWP.PropertyId = propId case 2: value, err := objects.DecReal(obj) if err != nil { - return decCWP, err + return decCWP, errors.Wrap(err, "decoding ConfirmedWP") } decCWP.Value = value case 4: priority, err := objects.DecPriority(obj) if err != nil { - return decCWP, err + return decCWP, errors.Wrap(err, "decoding ConfirmedWP") } decCWP.Priority = priority } From 8e8ca0c7aedaa4d2cdb8ed4a2fdd4cbcc7cab660 Mon Sep 17 00:00:00 2001 From: jonalfarlinga Date: Wed, 9 Oct 2024 13:00:30 -0500 Subject: [PATCH 8/8] removed break in whois-client that what added for debugging --- examples/whois-client.go | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/whois-client.go b/examples/whois-client.go index 88ae4c2..9ec4b99 100644 --- a/examples/whois-client.go +++ b/examples/whois-client.go @@ -76,7 +76,6 @@ func whoIsExample(cmd *cobra.Command, args []string) { break } log.Printf("got our own broadcast, back to listening...\n") - break } log.Printf("read %d bytes from %s: %x\n", nBytes, remoteAddr, replyRaw[:nBytes])