blob: e52d58798f97194b94c6ac8bbdcb8ddcdba7d5d3 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package main
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"unsafe"
)
////////////////////////////////////////////
// echo command
////////////////////////////////////////////
type echoCommand uint32
const (
echoCmd = iota
)
var echoCommandStrings = [...]string{
"echo",
}
func (c echoCommand) String() string {
return echoCommandStrings[c]
}
////////////////////////////////////////////
// EchoPkgHandler
////////////////////////////////////////////
const (
echoPkgMagic = 0x20160905
maxEchoStringLen = 0xff
)
var (
ErrNotEnoughStream = errors.New("packet stream is not enough")
ErrTooLargePackage = errors.New("package length is exceed the echo package's legal maximum length.")
ErrIllegalMagic = errors.New("package magic is not right.")
)
var echoPkgHeaderLen int
func init() {
echoPkgHeaderLen = (int)((uint)(unsafe.Sizeof(EchoPkgHeader{})))
}
type EchoPkgHeader struct {
Magic uint32
LogID uint32 // log id
Sequence uint32 // request/response sequence
ServiceID uint32 // service id
Command uint32 // operation command code
Code int32 // error code
Len uint16 // body length
_ uint16
_ int32 // reserved, maybe used as package md5 checksum
}
type EchoPackage struct {
H EchoPkgHeader
B string
}
func (p EchoPackage) String() string {
return fmt.Sprintf("log id:%d, sequence:%d, command:%s, echo string:%s",
p.H.LogID, p.H.Sequence, (echoCommand(p.H.Command)).String(), p.B)
}
func (p EchoPackage) Marshal() (*bytes.Buffer, error) {
var (
err error
buf *bytes.Buffer
)
buf = &bytes.Buffer{}
err = binary.Write(buf, binary.LittleEndian, p.H)
if err != nil {
return nil, err
}
buf.WriteByte((byte)(len(p.B)))
buf.WriteString(p.B)
return buf, nil
}
func (p *EchoPackage) Unmarshal(buf *bytes.Buffer) (int, error) {
var (
err error
len byte
)
if buf.Len() < echoPkgHeaderLen {
return 0, ErrNotEnoughStream
}
// header
err = binary.Read(buf, binary.LittleEndian, &(p.H))
if err != nil {
return 0, err
}
if p.H.Magic != echoPkgMagic {
log.Errorf("@p.H.Magic{%x}, right magic{%x}", p.H.Magic, echoPkgMagic)
return 0, ErrIllegalMagic
}
if buf.Len() < (int)(p.H.Len) {
return 0, ErrNotEnoughStream
}
// 防止恶意客户端把这个字段设置过大导致服务端死等或者服务端在准备对应的缓冲区时内存崩溃
if maxEchoStringLen < p.H.Len-1 {
return 0, ErrTooLargePackage
}
len, err = buf.ReadByte()
if err != nil {
return 0, nil
}
p.B = (string)(buf.Next((int)(len)))
return (int)(p.H.Len) + echoPkgHeaderLen, nil
}