98 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			98 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package pdu
 | |
| 
 | |
| import (
 | |
| 	"encoding/binary"
 | |
| 	"fmt"
 | |
| )
 | |
| 
 | |
| type (
 | |
| 	PDU interface {
 | |
| 		EncodeInto(*[]uint8)
 | |
| 		Encode() []uint8
 | |
| 		Decode([]uint8)
 | |
| 		// Size in bytes
 | |
| 		Size() uint32
 | |
| 	}
 | |
| 
 | |
| 	PDU_HEADER struct {
 | |
| 		command_length  uint32
 | |
| 		command_id      uint32
 | |
| 		command_status  uint32
 | |
| 		sequence_number uint32
 | |
| 	}
 | |
| 
 | |
| 	GENERIC_NACK struct {
 | |
| 		header PDU_HEADER
 | |
| 	}
 | |
| )
 | |
| 
 | |
| // Hmm the header can be partially encoded
 | |
| // As in command_status can just be null
 | |
| // So not 0s, null, non existent, not encoded
 | |
| // So we'll have to maybe set them to nil or something...
 | |
| // Wireshark dump of a submit_sm
 | |
| // See header: 00 00 00 3e (size, 62 bytes), 00 00 00 04 (command_id), status and sequence number are 0
 | |
| // So they are not encoded
 | |
| // Here the header is 8 bytes, not 16
 | |
| // 0000   02 00 00 00 45 00 00 66 6f ff 40 00 80 06 00 00   ....E..fo.@.....
 | |
| // 0010   7f 00 00 01 7f 00 00 01 31 4f 0a d7 e8 b0 b1 b5   ........1O......
 | |
| // 0020   3e 91 d9 dc 50 18 20 fa 2a 1f 00 00 00 00 00 3e   >...P. .*......>
 | |
| // 0030   00 00 00 04 00 00 00 00 00 00 00 02 00 00 00 73   ...............s
 | |
| // 0040   6d 70 70 5f 74 65 73 74 5f 31 00 00 00 31 32 33   mpp_test_1...123
 | |
| // 0050   31 32 33 31 32 33 31 32 33 00 00 00 00 00 00 00   123123123.......
 | |
| // 0060   00 c0 00 06 48 65 6c 6c 6f 21                     ....Hello!
 | |
| // I AM NOT RIGHT
 | |
| // Beyond the size and command_id, command_status and sequence_number here are:
 | |
| // 00 00 00 00 (0) 00 00 00 02 (2)
 | |
| //
 | |
| // Another example - bind_transciever:
 | |
| // 0000   02 00 00 00 45 00 00 47 6f fb 40 00 80 06 00 00   ....E..Go.@.....
 | |
| // 0010   7f 00 00 01 7f 00 00 01 31 4f 0a d7 e8 b0 b1 96   ........1O......
 | |
| // 0020   3e 91 d9 cb 50 18 20 fa df ab 00 00 00 00 00 1f   >...P. .........
 | |
| // 0030   00 00 00 09 00 00 00 00 00 00 00 01 74 65 73 74   ............test
 | |
| // 0040   00 74 65 73 74 00 00 50 00 00 00                  .test..P...
 | |
| // 00 00 00 1f - 00 00 00 09 - 00 00 00 00 - 00 00 00 01 (header)
 | |
| // 74 65 73 74 00 - 74 65 73 74 00 - 00 50 00 00 00
 | |
| // ^system_id       ^password           ^interface_version
 | |
| // What are the other 0s?
 | |
| // Don't know
 | |
| 
 | |
| func (p *PDU_HEADER) Encode() (*[]uint8, error) {
 | |
| 	buf := ByteBufferPool.Get(uint(p.Size()))
 | |
| 	err := p.EncodeInto(buf)
 | |
| 	return buf, err
 | |
| }
 | |
| func (p *PDU_HEADER) EncodeInto(buf *[]uint8) error {
 | |
| 	if buf == nil {
 | |
| 		return fmt.Errorf("cannot encode PDU_HEADER, buffer is nil")
 | |
| 	}
 | |
| 	if len(*buf) < 16 {
 | |
| 		return fmt.Errorf("cannot encode PDU_HEADER, buffer too small (%d, required 16)", len(*buf))
 | |
| 	}
 | |
| 	bufVal := *buf
 | |
| 	binary.BigEndian.PutUint32(bufVal[0:4], p.command_length)
 | |
| 	binary.BigEndian.PutUint32(bufVal[4:8], p.command_id)
 | |
| 	binary.BigEndian.PutUint32(bufVal[8:12], p.command_status)
 | |
| 	binary.BigEndian.PutUint32(bufVal[12:16], p.sequence_number)
 | |
| 	return nil
 | |
| }
 | |
| func (p *PDU_HEADER) Decode(data []uint8) error {
 | |
| 	if len(data) >= 4 {
 | |
| 		p.command_length = binary.BigEndian.Uint32(data[0:4])
 | |
| 	}
 | |
| 	if len(data) >= 8 {
 | |
| 		p.command_id = binary.BigEndian.Uint32(data[4:8])
 | |
| 	}
 | |
| 	if len(data) >= 12 {
 | |
| 		p.command_status = binary.BigEndian.Uint32(data[8:12])
 | |
| 
 | |
| 	}
 | |
| 	if len(data) >= 16 {
 | |
| 		p.sequence_number = binary.BigEndian.Uint32(data[12:16])
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| func (p *PDU_HEADER) Size() uint32 {
 | |
| 	return 16
 | |
| }
 | 
