diff --git a/example/transceiver_with_auto_response/main.go b/example/transceiver_with_auto_response/main.go index 37b9532..3392eb2 100644 --- a/example/transceiver_with_auto_response/main.go +++ b/example/transceiver_with_auto_response/main.go @@ -73,7 +73,7 @@ func sendingAndReceiveSMS(wg *sync.WaitGroup) { } func handlePDU() func(pdu.PDU, bool) { - concatenated := map[uint8][]string{} + concatenated := map[uint16][]string{} return func(p pdu.PDU, _ bool) { switch pd := p.(type) { case *pdu.SubmitSMResp: diff --git a/pdu/UDH.go b/pdu/UDH.go index de01743..68af3ed 100644 --- a/pdu/UDH.go +++ b/pdu/UDH.go @@ -7,7 +7,8 @@ import ( "github.com/linxGnu/gosmpp/data" ) -// For now, this package only support message uses of UDH for message concatenation +// This package supports message uses of UDH for message concatenation +// Both 8-bit and 16-bit reference numbers are supported for concatenated messages // No plan for supporting other Enhanced Messaging Service // Credit to https://github.com/warthog618/sms @@ -149,17 +150,29 @@ func (u UDH) FindInfoElement(id byte) (ie *InfoElement, found bool) { } // GetConcatInfo return the FIRST concatenated message IE, -func (u UDH) GetConcatInfo() (totalParts, partNum, mref byte, found bool) { +// For 8-bit reference, mref will be a byte value (0-255) +// For 16-bit reference, mref will be a uint16 value (0-65535) converted to uint +func (u UDH) GetConcatInfo() (totalParts, partNum byte, mref uint16, found bool) { if len(u) == 0 { found = false return } + // Check for 8-bit reference if ie, ok := u.FindInfoElement(data.UDH_CONCAT_MSG_8_BIT_REF); ok && len(ie.Data) == 3 { - mref = ie.Data[0] + mref = uint16(ie.Data[0]) totalParts = ie.Data[1] partNum = ie.Data[2] found = ok + return + } + + // Check for 16-bit reference + if ie, ok := u.FindInfoElement(data.UDH_CONCAT_MSG_16_BIT_REF); ok && len(ie.Data) == 4 { + mref = uint16(ie.Data[0])<<8 | uint16(ie.Data[1]) + totalParts = ie.Data[2] + partNum = ie.Data[3] + found = ok } return @@ -173,7 +186,7 @@ type InfoElement struct { Data []byte } -// NewIEConcatMessage turn a new IE element for concat message info +// NewIEConcatMessage creates a new IE element for 8-bit concat message info // IE.Data is populated at time of object creation func NewIEConcatMessage(totalParts, partNum, mref byte) InfoElement { return InfoElement{ @@ -182,6 +195,16 @@ func NewIEConcatMessage(totalParts, partNum, mref byte) InfoElement { } } +// NewIEConcatMessage16Bit creates a new IE element for 16-bit concat message info +// IE.Data is populated at time of object creation +// mref is a uint16 value (0-65535) +func NewIEConcatMessage16Bit(totalParts, partNum byte, mref uint16) InfoElement { + return InfoElement{ + ID: data.UDH_CONCAT_MSG_16_BIT_REF, + Data: []byte{byte(mref >> 8), byte(mref), byte(totalParts), byte(partNum)}, + } +} + // UnmarshalBinary unmarshal IE from binary in src, only read a single IE, // expect src at least of length 2 with correct IE format: // diff --git a/pdu/UDH_test.go b/pdu/UDH_test.go index 66ac447..7782fab 100644 --- a/pdu/UDH_test.go +++ b/pdu/UDH_test.go @@ -24,10 +24,23 @@ func TestUserDataHeader(t *testing.T) { require.True(t, found) require.Equal(t, totalParts, byte(2)) require.Equal(t, sequence, byte(1)) - require.Equal(t, reference, uint8(12)) + require.Equal(t, reference, uint(12)) }) - t.Run("unmarshalBinaryUDHConcatMessage", func(t *testing.T) { + t.Run("marshalBinaryUDHConcatMessage (16 bit)", func(t *testing.T) { + u := UDH{NewIEConcatMessage16Bit(2, 1, 1234)} + b, err := u.MarshalBinary() + require.NoError(t, err) + require.Equal(t, "06080404d20201", toHex(b)) + + totalParts, sequence, reference, found := u.GetConcatInfo() + require.True(t, found) + require.Equal(t, totalParts, byte(2)) + require.Equal(t, sequence, byte(1)) + require.Equal(t, reference, uint(1234)) + }) + + t.Run("unmarshalBinaryUDHConcatMessage (8 bit)", func(t *testing.T) { u, rd := new(UDH), []byte{0x05, 0x00, 0x03, 0x0c, 0x02, 0x01} read, err := u.UnmarshalBinary(rd) require.False(t, read <= 0) @@ -39,10 +52,29 @@ func TestUserDataHeader(t *testing.T) { require.Equal(t, "0500030c0201", toHex(b)) }) + t.Run("unmarshalBinaryUDHConcatMessage (16 bit)", func(t *testing.T) { + u, rd := new(UDH), []byte{0x06, 0x08, 0x04, 0x04, 0xd2, 0x02, 0x01} + read, err := u.UnmarshalBinary(rd) + require.False(t, read <= 0) + + require.NoError(t, err) + + totalParts, sequence, reference, found := u.GetConcatInfo() + require.True(t, found) + require.Equal(t, totalParts, byte(2)) + require.Equal(t, sequence, byte(1)) + require.Equal(t, reference, uint(1234)) + + b, err := u.MarshalBinary() + require.NoError(t, err) + require.Equal(t, "06080404d20201", toHex(b)) + }) + t.Run("unmarshalBinaryUDHConcatMessage failed", func(t *testing.T) { failedList := [][]byte{ - {0x04, 0x00, 0x02, 0x02, 0x01}, - {0x04, 0x08, 0x02, 0x02, 0x01}, + {0x04, 0x00, 0x02, 0x02, 0x01}, // Invalid 8-bit UDH (wrong length) + {0x04, 0x08, 0x02, 0x02, 0x01}, // Invalid 16-bit UDH (wrong length) + {0x05, 0x08, 0x03, 0x04, 0xd2, 0x01}, // Invalid 16-bit UDH (missing part number) } u := new(UDH) for _, data := range failedList {