// Copyright 2015 Tony Bai. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // See the License for the specific language governing permissions and // limitations under the License. package cmpp import ( "encoding/binary" "errors" ) // Packet length const for cmpp fwd request and response packets. const ( Cmpp2FwdReqPktMaxLen uint32 = 12 + 2379 //2277d, 0x957 Cmpp2FwdRspPktLen uint32 = 12 + 8 + 1 + 1 + 1 //23d, 0x17 Cmpp3FwdReqPktMaxLen uint32 = 12 + 2491 //2503d, 0x9c7 Cmpp3FwdRspPktLen uint32 = 12 + 8 + 1 + 1 + 4 //26d, 0x1a ) // Errors for result in fwd resp. var ( ErrnoFwdInvalidStruct uint8 = 1 ErrnoFwdInvalidCommandId uint8 = 2 ErrnoFwdInvalidSequence uint8 = 3 ErrnoFwdInvalidMsgLength uint8 = 4 ErrnoFwdInvalidFeeCode uint8 = 5 ErrnoFwdExceedMaxMsgLength uint8 = 6 ErrnoFwdInvalidServiceId uint8 = 7 ErrnoFwdNotPassFlowControl uint8 = 8 ErrnoFwdNoPrivilege uint8 = 9 FwdRspResultErrMap = map[uint8]error{ ErrnoFwdInvalidStruct: errFwdInvalidStruct, ErrnoFwdInvalidCommandId: errFwdInvalidCommandId, ErrnoFwdInvalidSequence: errFwdInvalidSequence, ErrnoFwdInvalidMsgLength: errFwdInvalidMsgLength, ErrnoFwdInvalidFeeCode: errFwdInvalidFeeCode, ErrnoFwdExceedMaxMsgLength: errFwdExceedMaxMsgLength, ErrnoFwdInvalidServiceId: errFwdInvalidServiceId, ErrnoFwdNotPassFlowControl: errFwdNotPassFlowControl, ErrnoFwdNoPrivilege: errFwdNoPrivilege, } errFwdInvalidStruct = errors.New("fwd response status: invalid protocol structure") errFwdInvalidCommandId = errors.New("fwd response status: invalid command id") errFwdInvalidSequence = errors.New("fwd response status: invalid message sequence") errFwdInvalidMsgLength = errors.New("fwd response status: invalid message length") errFwdInvalidFeeCode = errors.New("fwd response status: invalid fee code") errFwdExceedMaxMsgLength = errors.New("fwd response status: exceed max message length") errFwdInvalidServiceId = errors.New("fwd response status: invalid service id") errFwdNotPassFlowControl = errors.New("fwd response status: not pass the flow control") errFwdNoPrivilege = errors.New("fwd response status: msg has no fwd privilege") ) type Cmpp2FwdReqPkt struct { SourceId string DestinationId string NodesCount uint8 MsgFwdType uint8 MsgId uint64 PkTotal uint8 PkNumber uint8 RegisteredDelivery uint8 MsgLevel uint8 ServiceId string FeeUserType uint8 FeeTerminalId string TpPid uint8 TpUdhi uint8 MsgFmt uint8 MsgSrc string FeeType string FeeCode string ValidTime string AtTime string SrcId string DestUsrTl uint8 DestId []string MsgLength uint8 MsgContent string Reserve string // session info SeqId uint32 } type Cmpp2FwdRspPkt struct { MsgId uint64 PkTotal uint8 PkNumber uint8 Result uint8 // session info SeqId uint32 } type Cmpp3FwdReqPkt struct { SourceId string DestinationId string NodesCount uint8 MsgFwdType uint8 MsgId uint64 PkTotal uint8 PkNumber uint8 RegisteredDelivery uint8 MsgLevel uint8 ServiceId string FeeUserType uint8 FeeTerminalId string FeeTerminalPseudo string FeeTerminalUserType uint8 TpPid uint8 TpUdhi uint8 MsgFmt uint8 MsgSrc string FeeType string FeeCode string ValidTime string AtTime string SrcId string SrcPseudo string SrcUserType uint8 SrcType uint8 DestUsrTl uint8 DestId []string DestPseudo string DestUserType uint8 MsgLength uint8 MsgContent string LinkId string // session info SeqId uint32 } type Cmpp3FwdRspPkt struct { MsgId uint64 PkTotal uint8 PkNumber uint8 Result uint32 // session info SeqId uint32 } // Pack packs the Cmpp2FwdReqPkt to bytes stream for client side. // Before calling Pack, you should initialize a Cmpp2FwdReqPkt variable // with correct field value. func (p *Cmpp2FwdReqPkt) Pack(seqId uint32) ([]byte, error) { var pktLen uint32 = CMPP_HEADER_LEN + 131 + uint32(p.DestUsrTl)*21 + 1 + uint32(p.MsgLength) + 8 var w = newPacketWriter(pktLen) // Pack header w.WriteInt(binary.BigEndian, pktLen) w.WriteInt(binary.BigEndian, CMPP_FWD) w.WriteInt(binary.BigEndian, seqId) p.SeqId = seqId // Pack Body w.WriteFixedSizeString(p.SourceId, 6) w.WriteFixedSizeString(p.DestinationId, 6) w.WriteByte(p.NodesCount) w.WriteByte(p.MsgFwdType) w.WriteInt(binary.BigEndian, p.MsgId) if p.PkTotal == 0 && p.PkNumber == 0 { p.PkTotal, p.PkNumber = 1, 1 } w.WriteByte(p.PkTotal) w.WriteByte(p.PkNumber) w.WriteByte(p.RegisteredDelivery) w.WriteByte(p.MsgLevel) w.WriteFixedSizeString(p.ServiceId, 10) w.WriteByte(p.FeeUserType) w.WriteFixedSizeString(p.FeeTerminalId, 21) w.WriteByte(p.TpPid) w.WriteByte(p.TpUdhi) w.WriteByte(p.MsgFmt) w.WriteFixedSizeString(p.MsgSrc, 6) w.WriteFixedSizeString(p.FeeType, 2) w.WriteFixedSizeString(p.FeeCode, 6) w.WriteFixedSizeString(p.ValidTime, 17) w.WriteFixedSizeString(p.AtTime, 17) w.WriteFixedSizeString(p.SrcId, 21) w.WriteByte(p.DestUsrTl) for _, d := range p.DestId { w.WriteFixedSizeString(d, 21) } w.WriteByte(p.MsgLength) w.WriteString(p.MsgContent) w.WriteFixedSizeString(p.Reserve, 8) return w.Bytes() } // Unpack unpack the binary byte stream to a Cmpp2FwdReqPkt variable. // After unpack, you will get all value of fields in Cmpp2FwdReqPkt struct. func (p *Cmpp2FwdReqPkt) Unpack(data []byte) error { var r = newPacketReader(data) // Sequence Id r.ReadInt(binary.BigEndian, &p.SeqId) sourceId := r.ReadCString(6) p.SourceId = string(sourceId) destinationId := r.ReadCString(6) p.DestinationId = string(destinationId) p.NodesCount = r.ReadByte() p.MsgFwdType = r.ReadByte() r.ReadInt(binary.BigEndian, &p.MsgId) p.PkTotal = r.ReadByte() p.PkNumber = r.ReadByte() p.RegisteredDelivery = r.ReadByte() p.MsgLevel = r.ReadByte() serviceId := r.ReadCString(10) p.ServiceId = string(serviceId) p.FeeUserType = r.ReadByte() feeTerminalId := r.ReadCString(21) p.FeeTerminalId = string(feeTerminalId) p.TpPid = r.ReadByte() p.TpUdhi = r.ReadByte() p.MsgFmt = r.ReadByte() msgSrc := r.ReadCString(6) p.MsgSrc = string(msgSrc) feeType := make([]byte, 2) r.ReadBytes(feeType) p.FeeType = string(feeType) feeCode := r.ReadCString(6) p.FeeCode = string(feeCode) validTime := r.ReadCString(17) p.ValidTime = string(validTime) atTime := r.ReadCString(17) p.AtTime = string(atTime) srcId := r.ReadCString(21) p.SrcId = string(srcId) p.DestUsrTl = r.ReadByte() for i := 0; i < int(p.DestUsrTl); i++ { destId := r.ReadCString(21) p.DestId = append(p.DestId, string(destId)) } p.MsgLength = r.ReadByte() msgContent := make([]byte, p.MsgLength) r.ReadBytes(msgContent) p.MsgContent = string(msgContent) reserve := r.ReadCString(8) p.Reserve = string(reserve) return r.Error() } // Pack packs the Cmpp2FwdRspPkt to bytes stream for server side. // Before calling Pack, you should initialize a Cmpp2FwdRspPkt variable // with correct field value. func (p *Cmpp2FwdRspPkt) Pack(seqId uint32) ([]byte, error) { var pktLen = Cmpp2FwdRspPktLen var w = newPacketWriter(pktLen) // Pack header w.WriteInt(binary.BigEndian, pktLen) w.WriteInt(binary.BigEndian, CMPP_FWD_RESP) w.WriteInt(binary.BigEndian, seqId) p.SeqId = seqId // Pack Body w.WriteInt(binary.BigEndian, p.MsgId) w.WriteByte(p.PkTotal) w.WriteByte(p.PkNumber) w.WriteByte(p.Result) return w.Bytes() } // Unpack unpack the binary byte stream to a Cmpp2FwdRspPkt variable. // After unpack, you will get all value of fields in Cmpp2FwdRspPkt struct. func (p *Cmpp2FwdRspPkt) Unpack(data []byte) error { var r = newPacketReader(data) // Sequence Id r.ReadInt(binary.BigEndian, &p.SeqId) r.ReadInt(binary.BigEndian, &p.MsgId) p.PkTotal = r.ReadByte() p.PkNumber = r.ReadByte() p.Result = r.ReadByte() return r.Error() } // Pack packs the Cmpp3FwdReqPkt to bytes stream for client side. // Before calling Pack, you should initialize a Cmpp3FwdReqPkt variable // with correct field value. func (p *Cmpp3FwdReqPkt) Pack(seqId uint32) ([]byte, error) { var pktLen uint32 = CMPP_HEADER_LEN + 198 + uint32(p.DestUsrTl)*21 + 32 + 1 + 1 + uint32(p.MsgLength) + 20 var w = newPacketWriter(pktLen) // Pack header w.WriteInt(binary.BigEndian, pktLen) w.WriteInt(binary.BigEndian, CMPP_FWD) w.WriteInt(binary.BigEndian, seqId) p.SeqId = seqId // Pack Body w.WriteFixedSizeString(p.SourceId, 6) w.WriteFixedSizeString(p.DestinationId, 6) w.WriteByte(p.NodesCount) w.WriteByte(p.MsgFwdType) w.WriteInt(binary.BigEndian, p.MsgId) if p.PkTotal == 0 && p.PkNumber == 0 { p.PkTotal, p.PkNumber = 1, 1 } w.WriteByte(p.PkTotal) w.WriteByte(p.PkNumber) w.WriteByte(p.RegisteredDelivery) w.WriteByte(p.MsgLevel) w.WriteFixedSizeString(p.ServiceId, 10) w.WriteByte(p.FeeUserType) w.WriteFixedSizeString(p.FeeTerminalId, 21) w.WriteFixedSizeString(p.FeeTerminalPseudo, 32) w.WriteByte(p.FeeTerminalUserType) w.WriteByte(p.TpPid) w.WriteByte(p.TpUdhi) w.WriteByte(p.MsgFmt) w.WriteFixedSizeString(p.MsgSrc, 6) w.WriteFixedSizeString(p.FeeType, 2) w.WriteFixedSizeString(p.FeeCode, 6) w.WriteFixedSizeString(p.ValidTime, 17) w.WriteFixedSizeString(p.AtTime, 17) w.WriteFixedSizeString(p.SrcId, 21) w.WriteFixedSizeString(p.SrcPseudo, 32) w.WriteByte(p.SrcUserType) w.WriteByte(p.SrcType) w.WriteByte(p.DestUsrTl) for _, d := range p.DestId { w.WriteFixedSizeString(d, 21) } w.WriteFixedSizeString(p.DestPseudo, 32) w.WriteByte(p.DestUserType) w.WriteByte(p.MsgLength) w.WriteString(p.MsgContent) w.WriteFixedSizeString(p.LinkId, 20) return w.Bytes() } // Unpack unpack the binary byte stream to a Cmpp3FwdReqPkt variable. // After unpack, you will get all value of fields in Cmpp3FwdReqPkt struct. func (p *Cmpp3FwdReqPkt) Unpack(data []byte) error { var r = newPacketReader(data) // Sequence Id r.ReadInt(binary.BigEndian, &p.SeqId) // Body sourceId := r.ReadCString(6) p.SourceId = string(sourceId) destinationId := r.ReadCString(6) p.DestinationId = string(destinationId) p.NodesCount = r.ReadByte() p.MsgFwdType = r.ReadByte() r.ReadInt(binary.BigEndian, &p.MsgId) p.PkTotal = r.ReadByte() p.PkNumber = r.ReadByte() p.RegisteredDelivery = r.ReadByte() p.MsgLevel = r.ReadByte() serviceId := r.ReadCString(10) p.ServiceId = string(serviceId) p.FeeUserType = r.ReadByte() feeTerminalId := r.ReadCString(21) p.FeeTerminalId = string(feeTerminalId) feeTerminalPseudo := r.ReadCString(32) p.FeeTerminalPseudo = string(feeTerminalPseudo) p.FeeTerminalUserType = r.ReadByte() p.TpPid = r.ReadByte() p.TpUdhi = r.ReadByte() p.MsgFmt = r.ReadByte() msgSrc := r.ReadCString(6) p.MsgSrc = string(msgSrc) feeType := make([]byte, 2) r.ReadBytes(feeType) p.FeeType = string(feeType) feeCode := r.ReadCString(6) p.FeeCode = string(feeCode) validTime := r.ReadCString(17) p.ValidTime = string(validTime) atTime := r.ReadCString(17) p.AtTime = string(atTime) srcId := r.ReadCString(21) p.SrcId = string(srcId) srcPseudo := r.ReadCString(32) p.SrcPseudo = string(srcPseudo) p.SrcUserType = r.ReadByte() p.SrcType = r.ReadByte() p.DestUsrTl = r.ReadByte() for i := 0; i < int(p.DestUsrTl); i++ { destId := r.ReadCString(21) p.DestId = append(p.DestId, string(destId)) } destPseudo := r.ReadCString(32) p.DestPseudo = string(destPseudo) p.DestUserType = r.ReadByte() p.MsgLength = r.ReadByte() msgContent := make([]byte, p.MsgLength) r.ReadBytes(msgContent) p.MsgContent = string(msgContent) linkId := r.ReadCString(20) p.LinkId = string(linkId) return r.Error() } // Pack packs the Cmpp3FwdRspPkt to bytes stream for server side. // Before calling Pack, you should initialize a Cmpp3FwdRspPkt variable // with correct field value. func (p *Cmpp3FwdRspPkt) Pack(seqId uint32) ([]byte, error) { var pktLen = Cmpp3FwdRspPktLen var w = newPacketWriter(pktLen) // Pack header w.WriteInt(binary.BigEndian, pktLen) w.WriteInt(binary.BigEndian, CMPP_FWD_RESP) w.WriteInt(binary.BigEndian, seqId) p.SeqId = seqId // Pack Body w.WriteInt(binary.BigEndian, p.MsgId) w.WriteByte(p.PkTotal) w.WriteByte(p.PkNumber) w.WriteInt(binary.BigEndian, p.Result) return w.Bytes() } // Unpack unpack the binary byte stream to a Cmpp3FwdRspPkt variable. // After unpack, you will get all value of fields in Cmpp3FwdRspPkt struct. func (p *Cmpp3FwdRspPkt) Unpack(data []byte) error { var r = newPacketReader(data) // Sequence Id r.ReadInt(binary.BigEndian, &p.SeqId) r.ReadInt(binary.BigEndian, &p.MsgId) p.PkTotal = r.ReadByte() p.PkNumber = r.ReadByte() r.ReadInt(binary.BigEndian, &p.Result) return r.Error() }