go-smpp icon indicating copy to clipboard operation
go-smpp copied to clipboard

Decoded DeliverSM PDU differs from serialised one

Open Alexey1100 opened this issue 6 years ago • 5 comments

Looks like decoding process adds one null byte at the start of ShortMessage field.

Example code:

package main

import (
	"bytes"
	"fmt"

	"github.com/fiorix/go-smpp/smpp"
	"github.com/fiorix/go-smpp/smpp/pdu"
	"github.com/fiorix/go-smpp/smpp/pdu/pdufield"
	"github.com/fiorix/go-smpp/smpp/pdu/pdutext"
)

func main(){
	sm := &smpp.ShortMessage{
			Src:      "TEST",
			Dst:      "+79000005555",
			Text:     pdutext.UCS2("Hello"),
			Register: pdufield.NoDeliveryReceipt,
	}
	p := pdu.NewDeliverSM()
	f := p.Fields()
	f.Set(pdufield.SourceAddr, sm.Src)
	f.Set(pdufield.DestinationAddr, sm.Dst)
	f.Set(pdufield.ShortMessage, sm.Text)
	f.Set(pdufield.RegisteredDelivery, uint8(sm.Register))
	f.Set(pdufield.ServiceType, sm.ServiceType)
	f.Set(pdufield.SourceAddrTON, sm.SourceAddrTON)
	f.Set(pdufield.SourceAddrNPI, sm.SourceAddrNPI)
	f.Set(pdufield.DestAddrTON, sm.DestAddrTON)
	f.Set(pdufield.DestAddrNPI, sm.DestAddrNPI)
	f.Set(pdufield.ESMClass, sm.ESMClass)
	f.Set(pdufield.ProtocolID, sm.ProtocolID)
	f.Set(pdufield.PriorityFlag, sm.PriorityFlag)
	f.Set(pdufield.ScheduleDeliveryTime, sm.ScheduleDeliveryTime)
	f.Set(pdufield.ReplaceIfPresentFlag, sm.ReplaceIfPresentFlag)
	f.Set(pdufield.SMDefaultMsgID, sm.SMDefaultMsgID)
	f.Set(pdufield.DataCoding, uint8(sm.Text.Type()))

	var b bytes.Buffer
	p.SerializeTo(&b)
	fmt.Printf("INITIAL PDU: %x\n", b.Bytes())

	np, _ := pdu.Decode(bytes.NewBuffer(b.Bytes()))
	var nb bytes.Buffer
	np.SerializeTo(&nb)
	fmt.Printf("DECODED PDU: %x\n", nb.Bytes())

	fmt.Printf("INITIAL SM: %x\n", p.Fields()[pdufield.ShortMessage])
	fmt.Printf("DECODED SM: %x\n", np.Fields()[pdufield.ShortMessage])
}

Output:

$ go run smpp_sample.go
INITIAL PDU: 0000003c000000050000000000000001000000544553540000002b3739303030303035353535000000000000000008000a0000480065006c006c006f
DECODED PDU: 0000003c000000050000000000000001000000544553540000002b3739303030303035353535000000000000000008000a000000480065006c006c00
INITIAL SM: 00480065006c006c006f
DECODED SM: 0000480065006c006c00

Alexey1100 avatar Mar 24 '18 21:03 Alexey1100

Though, it works fine when dealing with SubmitSM PDU:

p := pdu.NewSubmitSM()
$ go run smpp_sample.go
INITIAL PDU: 0000003b000000040000000000000001000000544553540000002b3739303030303035353535000000000000000008000a00480065006c006c006f
DECODED PDU: 0000003b000000040000000000000001000000544553540000002b3739303030303035353535000000000000000008000a00480065006c006c006f
INITIAL SM: 00480065006c006c006f
DECODED SM: 00480065006c006c006f

Alexey1100 avatar Mar 25 '18 10:03 Alexey1100

Interesting. I haven't looked into this in a while, and haven't actually used this code for about a year now. If you can find where in the decoder we're adding that extra byte, please send a PR and I'll be happy to review.

fiorix avatar Mar 26 '18 09:03 fiorix

What I found at the moment, that it somehow refers to UDH parsing. Since when I'm removing UDHLength from pdufield.List in newDeliverSM, it decodes the example PDU just fine.

https://github.com/fiorix/go-smpp/blob/8eb557099ddf995af5b778652b1812f1ff86889c/smpp/pdu/types.go#L311

newSubmitSM doesn't have UDH fields defined for some reason.

Alexey1100 avatar Mar 28 '18 01:03 Alexey1100

This dirty hack seems to fix the problem, but I'm really not sure if it breaks something with an actual UDH.

// smpp/pdu/codec.go

// SerializeTo implements the PDU interface.
func (pdu *codec) SerializeTo(w io.Writer) error {
	var b bytes.Buffer
	for _, k := range pdu.FieldList() {
		f, ok := pdu.f[k]
		if !ok {
			// HACK: Skipping serialisation of UDH if it's not found in PDU
			if k == "gsm_sms_ud.udh.len" || k == "gsm_sms_ud.udh" {
			  continue
			}

			pdu.f.Set(k, nil)
			f = pdu.f[k]
		}
		if err := f.SerializeTo(&b); err != nil {
			return err
		}
	}
	for _, f := range pdu.TLVFields() {
		if err := f.SerializeTo(&b); err != nil {
			return err
		}
	}
	pdu.h.Len = uint32(pdu.Len())
	err := pdu.h.SerializeTo(w)
	if err != nil {
		return err
	}
	_, err = io.Copy(w, &b)
	return err
}

Alexey1100 avatar Apr 04 '18 01:04 Alexey1100

May be fixed by #94

mdouchement avatar Jan 25 '22 17:01 mdouchement