dubbo.apache.org/dubbo-go/v3@v3.1.1/protocol/dubbo/impl/codec.go (about)

     1  /*
     2   * Licensed to the Apache Software Foundation (ASF) under one or more
     3   * contributor license agreements.  See the NOTICE file distributed with
     4   * this work for additional information regarding copyright ownership.
     5   * The ASF licenses this file to You under the Apache License, Version 2.0
     6   * (the "License"); you may not use this file except in compliance with
     7   * the License.  You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  
    18  package impl
    19  
    20  import (
    21  	"bufio"
    22  	"encoding/binary"
    23  )
    24  
    25  import (
    26  	hessian "github.com/apache/dubbo-go-hessian2"
    27  
    28  	"github.com/dubbogo/gost/log/logger"
    29  
    30  	perrors "github.com/pkg/errors"
    31  )
    32  
    33  import (
    34  	"dubbo.apache.org/dubbo-go/v3/common/constant"
    35  	"dubbo.apache.org/dubbo-go/v3/remoting"
    36  )
    37  
    38  type ProtocolCodec struct {
    39  	reader     *bufio.Reader
    40  	pkgType    PackageType
    41  	bodyLen    int
    42  	serializer Serializer
    43  	headerRead bool
    44  }
    45  
    46  func (c *ProtocolCodec) ReadHeader(header *DubboHeader) error {
    47  	var err error
    48  	if c.reader.Size() < HEADER_LENGTH {
    49  		return hessian.ErrHeaderNotEnough
    50  	}
    51  	buf, err := c.reader.Peek(HEADER_LENGTH)
    52  	if err != nil { // this is impossible
    53  		return perrors.WithStack(err)
    54  	}
    55  	_, err = c.reader.Discard(HEADER_LENGTH)
    56  	if err != nil { // this is impossible
    57  		return perrors.WithStack(err)
    58  	}
    59  
    60  	//// read header
    61  	if buf[0] != MAGIC_HIGH && buf[1] != MAGIC_LOW {
    62  		return hessian.ErrIllegalPackage
    63  	}
    64  
    65  	// Header{serialization id(5 bit), event, two way, req/response}
    66  	if header.SerialID = buf[2] & SERIAL_MASK; header.SerialID == Zero {
    67  		return perrors.Errorf("serialization ID:%v", header.SerialID)
    68  	}
    69  
    70  	flag := buf[2] & FLAG_EVENT
    71  	if flag != Zero {
    72  		header.Type |= PackageHeartbeat
    73  	}
    74  	flag = buf[2] & FLAG_REQUEST
    75  	if flag != Zero {
    76  		header.Type |= PackageRequest
    77  		flag = buf[2] & FLAG_TWOWAY
    78  		if flag != Zero {
    79  			header.Type |= PackageRequest_TwoWay
    80  		}
    81  	} else {
    82  		header.Type |= PackageResponse
    83  		header.ResponseStatus = buf[3]
    84  		if header.ResponseStatus != Response_OK {
    85  			header.Type |= PackageResponse_Exception
    86  		}
    87  	}
    88  
    89  	// Header{req id}
    90  	header.ID = int64(binary.BigEndian.Uint64(buf[4:]))
    91  
    92  	// Header{body len}
    93  	header.BodyLen = int(binary.BigEndian.Uint32(buf[12:]))
    94  	if header.BodyLen < 0 {
    95  		return hessian.ErrIllegalPackage
    96  	}
    97  
    98  	c.pkgType = header.Type
    99  	c.bodyLen = header.BodyLen
   100  
   101  	if c.reader.Buffered() < c.bodyLen {
   102  		return hessian.ErrBodyNotEnough
   103  	}
   104  	c.headerRead = true
   105  	return perrors.WithStack(err)
   106  }
   107  
   108  func (c *ProtocolCodec) EncodeHeader(p DubboPackage) []byte {
   109  	header := p.Header
   110  	bs := make([]byte, 0)
   111  	switch header.Type {
   112  	case PackageHeartbeat:
   113  		if header.ResponseStatus == Zero {
   114  			bs = append(bs, hessian.DubboRequestHeartbeatHeader[:]...)
   115  		} else {
   116  			bs = append(bs, hessian.DubboResponseHeartbeatHeader[:]...)
   117  		}
   118  	case PackageResponse:
   119  		bs = append(bs, hessian.DubboResponseHeaderBytes[:]...)
   120  		if header.ResponseStatus != 0 {
   121  			bs[3] = header.ResponseStatus
   122  		}
   123  	case PackageRequest_TwoWay:
   124  		bs = append(bs, hessian.DubboRequestHeaderBytesTwoWay[:]...)
   125  	}
   126  	bs[2] |= header.SerialID & hessian.SERIAL_MASK
   127  	binary.BigEndian.PutUint64(bs[4:], uint64(header.ID))
   128  	return bs
   129  }
   130  
   131  func (c *ProtocolCodec) Encode(p DubboPackage) ([]byte, error) {
   132  	// header
   133  	if c.serializer == nil {
   134  		return nil, perrors.New("serializer should not be nil")
   135  	}
   136  	header := p.Header
   137  	switch header.Type {
   138  	case PackageHeartbeat:
   139  		if header.ResponseStatus == Zero {
   140  			return packRequest(p, c.serializer)
   141  		}
   142  		return packResponse(p, c.serializer)
   143  
   144  	case PackageRequest, PackageRequest_TwoWay:
   145  		return packRequest(p, c.serializer)
   146  
   147  	case PackageResponse:
   148  		return packResponse(p, c.serializer)
   149  
   150  	default:
   151  		return nil, perrors.Errorf("Unrecognized message type: %v", header.Type)
   152  	}
   153  }
   154  
   155  func (c *ProtocolCodec) Decode(p *DubboPackage) error {
   156  	if !c.headerRead {
   157  		if err := c.ReadHeader(&p.Header); err != nil {
   158  			return err
   159  		}
   160  	}
   161  	if c.reader.Size() < p.GetBodyLen() {
   162  		return hessian.ErrBodyNotEnough
   163  	}
   164  	body, err := c.reader.Peek(p.GetBodyLen())
   165  	if err != nil {
   166  		return err
   167  	}
   168  	if p.IsResponseWithException() {
   169  		logger.Infof("response with exception: %+v", p.Header)
   170  		decoder := hessian.NewDecoder(body)
   171  		p.Body = &ResponsePayload{}
   172  		exception, err := decoder.Decode()
   173  		if err != nil {
   174  			return perrors.WithStack(err)
   175  		}
   176  		p.Body.(*ResponsePayload).Exception = perrors.Errorf("java exception:%s", exception.(string))
   177  		return nil
   178  	} else if p.IsHeartBeat() {
   179  		// heartbeat no need to unmarshal contents
   180  		return nil
   181  	}
   182  	if c.serializer == nil {
   183  		return perrors.New("Codec serializer is nil")
   184  	}
   185  	if p.IsResponse() {
   186  		p.Body = &ResponsePayload{
   187  			RspObj: remoting.GetPendingResponse(remoting.SequenceType(p.Header.ID)).Reply,
   188  		}
   189  	}
   190  	return c.serializer.Unmarshal(body, p)
   191  }
   192  
   193  func (c *ProtocolCodec) SetSerializer(serializer Serializer) {
   194  	c.serializer = serializer
   195  }
   196  
   197  func packRequest(p DubboPackage, serializer Serializer) ([]byte, error) {
   198  	var (
   199  		byteArray []byte
   200  		pkgLen    int
   201  	)
   202  
   203  	header := p.Header
   204  
   205  	//////////////////////////////////////////
   206  	// byteArray
   207  	//////////////////////////////////////////
   208  	// magic
   209  	switch header.Type {
   210  	case PackageHeartbeat:
   211  		byteArray = append(byteArray, DubboRequestHeartbeatHeader[:]...)
   212  	case PackageRequest_TwoWay:
   213  		byteArray = append(byteArray, DubboRequestHeaderBytesTwoWay[:]...)
   214  	default:
   215  		byteArray = append(byteArray, DubboRequestHeaderBytes[:]...)
   216  	}
   217  
   218  	// serialization id, two way flag, event, request/response flag
   219  	// SerialID is id of serialization approach in java dubbo
   220  	byteArray[2] |= header.SerialID & SERIAL_MASK
   221  	// request id
   222  	binary.BigEndian.PutUint64(byteArray[4:], uint64(header.ID))
   223  
   224  	//////////////////////////////////////////
   225  	// body
   226  	//////////////////////////////////////////
   227  	if p.IsHeartBeat() {
   228  		byteArray = append(byteArray, byte('N'))
   229  		pkgLen = 1
   230  	} else {
   231  		body, err := serializer.Marshal(p)
   232  		if err != nil {
   233  			return nil, err
   234  		}
   235  		pkgLen = len(body)
   236  		if pkgLen > int(DEFAULT_LEN) { // recommand 8M
   237  			logger.Warnf("Data length %d too large, recommand max payload %d. "+
   238  				"Dubbo java can't handle the package whose size is greater than %d!!!", pkgLen, DEFAULT_LEN, DEFAULT_LEN)
   239  		}
   240  		byteArray = append(byteArray, body...)
   241  	}
   242  	binary.BigEndian.PutUint32(byteArray[12:], uint32(pkgLen))
   243  	return byteArray, nil
   244  }
   245  
   246  func packResponse(p DubboPackage, serializer Serializer) ([]byte, error) {
   247  	var byteArray []byte
   248  	header := p.Header
   249  	hb := p.IsHeartBeat()
   250  
   251  	// magic
   252  	if hb {
   253  		byteArray = append(byteArray, DubboResponseHeartbeatHeader[:]...)
   254  	} else {
   255  		byteArray = append(byteArray, DubboResponseHeaderBytes[:]...)
   256  	}
   257  	// set serialID, identify serialization types, eg: fastjson->6, hessian2->2
   258  	byteArray[2] |= header.SerialID & SERIAL_MASK
   259  	// response status
   260  	if header.ResponseStatus != 0 {
   261  		byteArray[3] = header.ResponseStatus
   262  	}
   263  
   264  	// request id
   265  	binary.BigEndian.PutUint64(byteArray[4:], uint64(header.ID))
   266  
   267  	// body
   268  	body, err := serializer.Marshal(p)
   269  	if err != nil {
   270  		return nil, err
   271  	}
   272  
   273  	pkgLen := len(body)
   274  	if pkgLen > int(DEFAULT_LEN) { // recommand 8M
   275  		logger.Warnf("Data length %d too large, recommand max payload %d. "+
   276  			"Dubbo java can't handle the package whose size is greater than %d!!!", pkgLen, DEFAULT_LEN, DEFAULT_LEN)
   277  	}
   278  	// byteArray{body length}
   279  	binary.BigEndian.PutUint32(byteArray[12:], uint32(pkgLen))
   280  	byteArray = append(byteArray, body...)
   281  	return byteArray, nil
   282  }
   283  
   284  func NewDubboCodec(reader *bufio.Reader) *ProtocolCodec {
   285  	s, _ := GetSerializerById(constant.SHessian2)
   286  	return &ProtocolCodec{
   287  		reader:     reader,
   288  		pkgType:    0,
   289  		bodyLen:    0,
   290  		headerRead: false,
   291  		serializer: s,
   292  	}
   293  }