加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
packet.go 8.67 KB
一键复制 编辑 原始数据 按行查看 历史
// 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 (
"bytes"
"encoding/binary"
"errors"
"fmt"
"strings"
)
type Type int8
const (
V30 Type = 0x30
V21 Type = 0x21
V20 Type = 0x20
)
func (t Type) String() string {
switch {
case t == V30:
return "cmpp30"
case t == V21:
return "cmpp21"
case t == V20:
return "cmpp20"
default:
return "unknown"
}
}
const (
CMPP_HEADER_LEN uint32 = 12
CMPP2_PACKET_MAX uint32 = 2477
CMPP2_PACKET_MIN uint32 = 12
CMPP3_PACKET_MAX uint32 = 3335
CMPP3_PACKET_MIN uint32 = 12
)
// Common errors.
var ErrMethodParamsInvalid = errors.New("params passed to method is invalid")
// Protocol errors.
var ErrTotalLengthInvalid = errors.New("total_length in Packet data is invalid")
var ErrCommandIdInvalid = errors.New("command_Id in Packet data is invalid")
var ErrCommandIdNotSupported = errors.New("command_Id in Packet data is not supported")
type CommandId uint32
const (
CMPP_REQUEST_MIN, CMPP_RESPONSE_MIN CommandId = iota, 0x80000000 + iota
CMPP_CONNECT, CMPP_CONNECT_RESP
CMPP_TERMINATE, CMPP_TERMINATE_RESP
_, _
CMPP_SUBMIT, CMPP_SUBMIT_RESP
CMPP_DELIVER, CMPP_DELIVER_RESP
CMPP_QUERY, CMPP_QUERY_RESP
CMPP_CANCEL, CMPP_CANCEL_RESP
CMPP_ACTIVE_TEST, CMPP_ACTIVE_TEST_RESP
CMPP_FWD, CMPP_FWD_RESP
CMPP_MT_ROUTE, CMPP_MT_ROUTE_RESP CommandId = 0x00000010 - 10 + iota, 0x80000010 - 10 + iota
CMPP_MO_ROUTE, CMPP_MO_ROUTE_RESP
CMPP_GET_MT_ROUTE, CMPP_GET_MT_ROUTE_RESP
CMPP_MT_ROUTE_UPDATE, CMPP_MT_ROUTE_UPDATE_RESP
CMPP_MO_ROUTE_UPDATE, CMPP_MO_ROUTE_UPDATE_RESP
CMPP_PUSH_MT_ROUTE_UPDATE, CMPP_PUSH_MT_ROUTE_UPDATE_RESP
CMPP_PUSH_MO_ROUTE_UPDATE, CMPP_PUSH_MO_ROUTE_UPDATE_RESP
CMPP_GET_MO_ROUTE, CMPP_GET_MO_ROUTE_RESP
CMPP_REQUEST_MAX, CMPP_RESPONSE_MAX
)
func (id CommandId) String() string {
if id <= CMPP_FWD && id > CMPP_REQUEST_MIN {
return []string{
"CMPP_CONNECT",
"CMPP_TERMINATE",
"CMPP_UNKNOWN",
"CMPP_SUBMIT",
"CMPP_DELIVER",
"CMPP_QUERY",
"CMPP_CANCEL",
"CMPP_ACTIVE_TEST",
"CMPP_FWD",
}[id-1]
} else if id >= CMPP_MT_ROUTE && id < CMPP_REQUEST_MAX {
return []string{
"CMPP_MT_ROUTE",
"CMPP_MO_ROUTE",
"CMPP_GET_MT_ROUTE",
"CMPP_MT_ROUTE_UPDATE",
"CMPP_MO_ROUTE_UPDATE",
"CMPP_PUSH_MT_ROUTE_UPDATE",
"CMPP_PUSH_MO_ROUTE_UPDATE",
"CMPP_GET_MO_ROUTE",
}[id-0x00000010]
}
if id <= CMPP_FWD_RESP && id > CMPP_RESPONSE_MIN {
return []string{
"CMPP_CONNECT_RESP",
"CMPP_TERMINATE_RESP",
"CMPP_UNKNOWN",
"CMPP_SUBMIT_RESP",
"CMPP_DELIVER_RESP",
"CMPP_QUERY_RESP",
"CMPP_CANCEL_RESP",
"CMPP_ACTIVE_TEST_RESP",
"CMPP_FWD_RESP",
}[id-0x80000001]
} else if id >= CMPP_MT_ROUTE_RESP && id < CMPP_RESPONSE_MAX {
return []string{
"CMPP_MT_ROUTE_RESP",
"CMPP_MO_ROUTE_RESP",
"CMPP_GET_MT_ROUTE_RESP",
"CMPP_MT_ROUTE_UPDATE_RESP",
"CMPP_MO_ROUTE_UPDATE_RESP",
"CMPP_PUSH_MT_ROUTE_UPDATE_RESP",
"CMPP_PUSH_MO_ROUTE_UPDATE_RESP",
"CMPP_GET_MO_ROUTE_RESP",
}[id-0x80000010]
}
return "unknown"
}
type Packer interface {
Pack(seqId uint32) ([]byte, error)
Unpack(data []byte) error
}
// OpError is the error type usually returned by functions in the cmpppacket
// package. It describes the operation and the error which the operation caused.
type OpError struct {
// err is the error that occurred during the operation.
// it is the origin error.
err error
// op is the operation which caused the error, such as
// some "read" or "write" in packetWriter or packetReader.
op string
}
func NewOpError(e error, op string) *OpError {
return &OpError{
err: e,
op: op,
}
}
func (e *OpError) Error() string {
if e.err == nil {
return "<nil>"
}
return e.op + " error: " + e.err.Error()
}
func (e *OpError) Cause() error {
return e.err
}
func (e *OpError) Op() string {
return e.op
}
type packetWriter struct {
wb *bytes.Buffer
err *OpError
}
func newPacketWriter(initSize uint32) *packetWriter {
buf := make([]byte, 0, initSize)
return &packetWriter{
wb: bytes.NewBuffer(buf),
}
}
// Bytes returns a slice of the contents of the inner buffer;
// If the caller changes the contents of the
// returned slice, the contents of the buffer will change provided there
// are no intervening method calls on the Buffer.
func (w *packetWriter) Bytes() ([]byte, error) {
if w.err != nil {
return nil, w.err
}
len := w.wb.Len()
return (w.wb.Bytes())[:len], nil
}
// WriteByte appends the byte of b to the inner buffer, growing the buffer as
// needed.
func (w *packetWriter) WriteByte(b byte) {
if w.err != nil {
return
}
err := w.wb.WriteByte(b)
if err != nil {
w.err = NewOpError(err,
fmt.Sprintf("packetWriter.WriteByte writes: %x", b))
return
}
}
// WriteFixedSizeString writes a string to buffer, if the length of s is less than size,
// Pad binary zero to the right.
func (w *packetWriter) WriteFixedSizeString(s string, size int) {
if w.err != nil {
return
}
l1 := len(s)
l2 := l1
if l2 > 10 {
l2 = 10
}
if l1 > size {
w.err = NewOpError(ErrMethodParamsInvalid,
fmt.Sprintf("packetWriter.WriteFixedSizeString writes: %s", s[0:l2]))
return
}
w.WriteString(strings.Join([]string{s, string(make([]byte, size-l1))}, ""))
}
// WriteString appends the contents of s to the inner buffer, growing the buffer as
// needed.
func (w *packetWriter) WriteString(s string) {
if w.err != nil {
return
}
l1 := len(s)
l2 := l1
if l2 > 10 {
l2 = 10
}
n, err := w.wb.WriteString(s)
if err != nil {
w.err = NewOpError(err,
fmt.Sprintf("packetWriter.WriteString writes: %s", s[0:l2]))
return
}
if n != l1 {
w.err = NewOpError(fmt.Errorf("WriteString writes %d bytes, not equal to %d we expected", n, l1),
fmt.Sprintf("packetWriter.WriteString writes: %s", s[0:l2]))
return
}
}
// WriteInt appends the content of data to the inner buffer in order, growing the buffer as
// needed.
func (w *packetWriter) WriteInt(order binary.ByteOrder, data interface{}) {
if w.err != nil {
return
}
err := binary.Write(w.wb, order, data)
if err != nil {
w.err = NewOpError(err,
fmt.Sprintf("packetWriter.WriteInt writes: %#v", data))
return
}
}
const maxCStringSize = 160
type packetReader struct {
rb *bytes.Buffer
err *OpError
cbuf [maxCStringSize]byte
}
func newPacketReader(data []byte) *packetReader {
return &packetReader{
rb: bytes.NewBuffer(data),
}
}
// ReadByte reads and returns the next byte from the inner buffer.
// If no byte is available, it returns an OpError.
func (r *packetReader) ReadByte() byte {
if r.err != nil {
return 0
}
b, err := r.rb.ReadByte()
if err != nil {
r.err = NewOpError(err,
"packetReader.ReadByte")
return 0
}
return b
}
// ReadInt reads reads structured binary data from r into data.
// Data must be a pointer to a fixed-size value or a slice
// of fixed-size values.
// Bytes read from r are decoded using the specified byte order
// and written to successive fields of the data.
func (r *packetReader) ReadInt(order binary.ByteOrder, data interface{}) {
if r.err != nil {
return
}
err := binary.Read(r.rb, order, data)
if err != nil {
r.err = NewOpError(err,
"packetReader.ReadInt")
return
}
}
// ReadBytes reads the next len(s) bytes from the inner buffer to s.
// If the buffer has no data to return, an OpError would be stored in r.err.
func (r *packetReader) ReadBytes(s []byte) {
if r.err != nil {
return
}
n, err := r.rb.Read(s)
if err != nil {
r.err = NewOpError(err,
"packetReader.ReadBytes")
return
}
if n != len(s) {
r.err = NewOpError(fmt.Errorf("ReadBytes reads %d bytes, not equal to %d we expected", n, len(s)),
"packetWriter.ReadBytes")
return
}
}
// ReadCString read bytes from packerReader's inner buffer,
// it would trim the tail-zero byte and the bytes after that.
func (r *packetReader) ReadCString(length int) []byte {
if r.err != nil {
return nil
}
var tmp = r.cbuf[:length]
n, err := r.rb.Read(tmp)
if err != nil {
r.err = NewOpError(err,
"packetReader.ReadCString")
return nil
}
if n != length {
r.err = NewOpError(fmt.Errorf("ReadCString reads %d bytes, not equal to %d we expected", n, length),
"packetWriter.ReadCString")
return nil
}
i := bytes.IndexByte(tmp, 0)
if i == -1 {
return tmp
} else {
return tmp[:i]
}
}
// Error return the inner err.
func (r *packetReader) Error() error {
if r.err != nil {
return r.err
}
return nil
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化