go-smpp
go-smpp copied to clipboard
Decoded DeliverSM PDU differs from serialised one
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
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
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.
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.
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
}
May be fixed by #94