Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Cr #28

Closed
wants to merge 7 commits into from
Closed

Cr #28

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
175 changes: 175 additions & 0 deletions cc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
package sccp

import (
"fmt"
"io"

"github.com/wmnsk/go-sccp/params"
)

/*
Message type 2.1 F 1
Destination local reference 3.2 F 3
Source local reference 3.3 F 3
Protocol class 3.6 F 1
Credit 3.10 O 3
Called party address 3.4 O 4 minimum
Data 3.16 O 3-130
Importance 3.19 O 3
End of optional parameter 3.1 O 1
*/
type CC struct {
Type MsgType
DestinationLocalReference params.LocalReference
SourceLocalReference params.LocalReference
params.ProtocolClass

Opts []*params.Optional

Data *params.Optional
CalledPartyAddress *params.PartyAddress
}

func ParseCC(b []byte) (*CC, error) {
msg := &CC{}
if err := msg.UnmarshalBinary(b); err != nil {
return nil, err
}

return msg, nil
}

func (msg *CC) UnmarshalBinary(b []byte) error {
l := uint8(len(b))

if l < (1 + 3 + 3 + 1 + 1) {
return io.ErrUnexpectedEOF
}

msg.Type = MsgType(b[0])
if err := msg.DestinationLocalReference.Read(b[1:4]); err != nil {
return err
}
if err := msg.SourceLocalReference.Read(b[4:7]); err != nil {
return err
}

msg.ProtocolClass = params.ProtocolClass(b[7])

optr := b[8]

if optr == 0 {
return nil
}
if optr != 1 {
return io.ErrUnexpectedEOF
}

if err := msg.parseOptional(b[9:]); err != nil {
return io.ErrUnexpectedEOF
}
return nil
}

func (msg *CC) parseOptional(b []byte) error {
p := uint8(0)
for p < uint8(len(b)) {
t := b[p]

if t == 0 {
return nil
}
if (p + 1) >= uint8(len(b)) {
return io.ErrUnexpectedEOF
}

l := b[p+1]
if (p + 1 + l) >= uint8(len(b)) {
return io.ErrUnexpectedEOF
}

o := &params.Optional{
Tag: t,
Len: l,
Value: b[p+2 : p+2+l],
}

switch t {
case params.DataTag:
msg.Data = o
case params.CdPtyAddrTag:
var err error
msg.CalledPartyAddress, err = params.ParsePartyAddress(b[p : p+2+l])
if err != nil {
return err
}
}

msg.Opts = append(msg.Opts, o)
p += 2 + l

}

return nil
}

// MarshalBinary returns the byte sequence generated from a UDT instance.
func (msg *CC) MarshalBinary() ([]byte, error) {
b := make([]byte, msg.MarshalLen())
if err := msg.MarshalTo(b); err != nil {
return nil, err
}

return b, nil
}

func (msg *CC) MarshalLen() int {
if len(msg.Opts) == 0 {
return 9 // 8 fixed + 0 ptr
}
l := 10 // 8 fixed + 1 ptr + last optional
for _, v := range msg.Opts {
l += int(v.Len) + 2
}

return l
}

func (msg *CC) MarshalTo(b []byte) error {
b[0] = uint8(msg.Type)
msg.DestinationLocalReference.Read(b[1:4])

Check failure on line 140 in cc.go

View workflow job for this annotation

GitHub Actions / lint

Error return value of `msg.DestinationLocalReference.Read` is not checked (errcheck)
msg.SourceLocalReference.Read(b[4:7])

Check failure on line 141 in cc.go

View workflow job for this annotation

GitHub Actions / lint

Error return value of `msg.SourceLocalReference.Read` is not checked (errcheck)
b[7] = byte(msg.ProtocolClass)

if len(msg.Opts) == 0 {
return nil
}

b[8] = 1
p := uint8(9)

for i := 0; i < len(msg.Opts); i++ {
b[p] = msg.Opts[i].Tag
b[p+1] = msg.Opts[i].Len
copy(b[p+2:], msg.Opts[i].Value)

p += msg.Opts[i].Len + 2
}
return nil
}

func (msg *CC) String() string {
if msg.CalledPartyAddress != nil {
return fmt.Sprintf("{Type: CC, CalledPartyAddress: %v}", msg.CalledPartyAddress)
}
return "{Type: CC}"
}

// MessageType returns the Message Type in int.
func (msg *CC) MessageType() MsgType {
return msg.Type
}

func (msg *CC) MessageTypeName() string {
return "CR"
}
33 changes: 33 additions & 0 deletions cc_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package sccp

import (
"bytes"
"encoding/hex"
"fmt"
"testing"
)

var mockCCs = [][]byte{
{0x2, 0x0, 0x3, 0x75, 0x3, 0x20, 0x48, 0x2, 0x0},
{0x2, 0x0, 0x70, 0x3e, 0x0, 0x0, 0x5, 0x2, 0x1, 0x3, 0x4, 0x43, 0x1c, 0x2d, 0xfe, 0x0},
}

func TestCC(t *testing.T) {
for i, v := range mockCCs {
cc, err := ParseCC(v)
if err != nil {
t.Fatal(i, err)
}
b, err := cc.MarshalBinary()
if err != nil {
t.Fatal(i, err)
}
if !bytes.Equal(v, b) {
fmt.Println(hex.EncodeToString(v))
fmt.Println(hex.EncodeToString(b))

t.Fatal(i, err)
}
fmt.Println(cc)
}
}
182 changes: 182 additions & 0 deletions cr.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
package sccp

import (
"encoding/hex"
"fmt"
"io"

"github.com/wmnsk/go-sccp/params"
)

/*
Message type code 2.1 F 1
Source local reference 3.3 F 3
Protocol class 3.6 F 1
Called party address 3.4 V 3 minimum
Credit 3.10 O 3
Calling party address 3.5 O 4 minimum
Data 3.16 O 3-130
Hop counter 3.18 O 3
Importance 3.19 O 3
End of optional parameters 3.1 O 1
*/

type CR struct {
Type MsgType
SourceLocalReference params.LocalReference
params.ProtocolClass
CalledPartyAddress *params.PartyAddress

Opts []*params.Optional // all others

// just pointers, not used for Marshal-ing, I kust really need these two
// similar objects are expected to be found in Opts
Data *params.Optional
CallingPartyAddress *params.PartyAddress

mptr uint8
optr uint8
}

func ParseCR(b []byte) (*CR, error) {
msg := &CR{}
if err := msg.UnmarshalBinary(b); err != nil {
return nil, err
}

return msg, nil
}

func (msg *CR) UnmarshalBinary(b []byte) error {
l := uint8(len(b))
if l <= (1 + 3 + 1 + 2 /*ptrs*/ + 3) { // where CdPA starts
return io.ErrUnexpectedEOF
}

msg.Type = MsgType(b[0])
if err := msg.SourceLocalReference.Read(b[1:4]); err != nil {
return err
}
msg.ProtocolClass = params.ProtocolClass(b[4])

msg.mptr = b[5]
if l < (5 + msg.mptr + 2) {
return io.ErrUnexpectedEOF
}
msg.optr = b[6]
if l < (6 + msg.optr + 1) {
return io.ErrUnexpectedEOF
}

var err error
if msg.CalledPartyAddress, err = params.ParsePartyAddress(b[5+msg.mptr : 6+msg.optr]); err != nil {
return err
}
if msg.optr == 0 {
return nil
}
return msg.parseOptional(b[6+msg.optr:])
}

func (msg *CR) parseOptional(b []byte) error {
p := uint8(0)
for p < uint8(len(b)) {
t := b[p]

if t == 0 {
return nil
}
if (p + 1) >= uint8(len(b)) {
return io.ErrUnexpectedEOF
}

l := b[p+1]
if (p + 1 + l) >= uint8(len(b)) {
return io.ErrUnexpectedEOF
}

o := &params.Optional{
Tag: t,
Len: l,
Value: b[p+2 : p+2+l],
}

switch t {
case params.DataTag:
msg.Data = o
case params.CgPtyAddrTag:
var err error
msg.CallingPartyAddress, err = params.ParsePartyAddress(b[p : p+2+l])
if err != nil {
return err
}
}

msg.Opts = append(msg.Opts, o)
p += 2 + l

}

return nil
}

// MarshalBinary returns the byte sequence generated from a UDT instance.
func (msg *CR) MarshalBinary() ([]byte, error) {
b := make([]byte, msg.MarshalLen())
if err := msg.MarshalTo(b); err != nil {
return nil, err
}

return b, nil
}

func (msg *CR) MarshalLen() int {
l := 5 + 2 + 1 // fixed + ptrs + last optional
for _, v := range msg.Opts {
l += int(v.Len) + 2
}
l += int(msg.CalledPartyAddress.Length) + 1

return l
}

func (msg *CR) MarshalTo(b []byte) error {
b[0] = uint8(msg.Type)
msg.SourceLocalReference.Read(b[1:4])

Check failure on line 145 in cr.go

View workflow job for this annotation

GitHub Actions / lint

Error return value of `msg.SourceLocalReference.Read` is not checked (errcheck)
b[4] = byte(msg.ProtocolClass)
b[5] = 2
b[6] = msg.CalledPartyAddress.Length + 2
if err := msg.CalledPartyAddress.MarshalTo(b[7 : 7+int(msg.CalledPartyAddress.Length)+1]); err != nil {
return err
}
p := 6 + msg.CalledPartyAddress.Length + 1 + 1
for i := 0; i < len(msg.Opts); i++ {
b[p] = msg.Opts[i].Tag
b[p+1] = msg.Opts[i].Len
copy(b[p+2:], msg.Opts[i].Value)

p += msg.Opts[i].Len + 2
}
return nil
}

func (msg *CR) String() string {
s := fmt.Sprintf("{Type: CR, CalledPartyAddress: %v", msg.CalledPartyAddress)
if msg.CallingPartyAddress != nil {
s += fmt.Sprintf(", CallingPartyAddress: %v", msg.CallingPartyAddress)
}
if msg.Data != nil {
s += fmt.Sprintf(", DataLength: %d, Data: %s", msg.Data.Len, hex.EncodeToString(msg.Data.Value))
}

return s + "}"
}

// MessageType returns the Message Type in int.
func (msg *CR) MessageType() MsgType {
return msg.Type
}

func (msg *CR) MessageTypeName() string {
return "CR"
}
Loading
Loading