X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=codec%2Fmsg_codec.go;h=227764d0eb7760dddf748066a022c6d1517b3d23;hb=8d3131f90f71271835e5fed91831565797894614;hp=7ba87711b2d00c6ac70ddd94747bcaffed92d88b;hpb=a679bbc78b98089f9b221bbe7de963f5274073bb;p=govpp.git diff --git a/codec/msg_codec.go b/codec/msg_codec.go index 7ba8771..227764d 100644 --- a/codec/msg_codec.go +++ b/codec/msg_codec.go @@ -15,127 +15,116 @@ package codec import ( - "bytes" + "encoding/binary" "errors" "fmt" - "reflect" "git.fd.io/govpp.git/api" - "github.com/lunixbochs/struc" ) -// MsgCodec provides encoding and decoding functionality of `api.Message` structs into/from -// binary format as accepted by VPP. -type MsgCodec struct{} - -// VppRequestHeader struct contains header fields implemented by all VPP requests. -type VppRequestHeader struct { - VlMsgID uint16 - ClientIndex uint32 - Context uint32 -} +var DefaultCodec = new(MsgCodec) -// VppReplyHeader struct contains header fields implemented by all VPP replies. -type VppReplyHeader struct { - VlMsgID uint16 - Context uint32 +func EncodeMsg(msg api.Message, msgID uint16) (data []byte, err error) { + return DefaultCodec.EncodeMsg(msg, msgID) } - -// VppEventHeader struct contains header fields implemented by all VPP events. -type VppEventHeader struct { - VlMsgID uint16 - Context uint32 +func DecodeMsg(data []byte, msg api.Message) (err error) { + return DefaultCodec.DecodeMsg(data, msg) } - -// VppOtherHeader struct contains header fields implemented by other VPP messages (not requests nor replies). -type VppOtherHeader struct { - VlMsgID uint16 +func DecodeMsgContext(data []byte, msgType api.MessageType) (context uint32, err error) { + return DefaultCodec.DecodeMsgContext(data, msgType) } -const ( - vppRequestHeaderSize = 10 // size of a VPP request header - vppReplyHeaderSize = 6 // size of a VPP reply header - vppEventHeaderSize = 6 // size of a VPP event header - vppOtherHeaderSize = 2 // size of the header of other VPP messages -) +// MsgCodec provides encoding and decoding functionality of `api.Message` structs into/from +// binary format as accepted by VPP. +type MsgCodec struct{} -// EncodeMsg encodes provided `Message` structure into its binary-encoded data representation. -func (*MsgCodec) EncodeMsg(msg api.Message, msgID uint16) ([]byte, error) { +func (*MsgCodec) EncodeMsg(msg api.Message, msgID uint16) (data []byte, err error) { if msg == nil { return nil, errors.New("nil message passed in") } - buf := new(bytes.Buffer) - - // encode message header - var header interface{} - if msg.GetMessageType() == api.RequestMessage { - header = &VppRequestHeader{VlMsgID: msgID} - } else if msg.GetMessageType() == api.ReplyMessage { - header = &VppReplyHeader{VlMsgID: msgID} - } else if msg.GetMessageType() == api.EventMessage { - header = &VppEventHeader{VlMsgID: msgID} - } else { - header = &VppOtherHeader{VlMsgID: msgID} - } - err := struc.Pack(buf, header) - if err != nil { - return nil, fmt.Errorf("unable to encode message: header: %v, error %v", header, err) + // try to recover panic which might possibly occur + defer func() { + if r := recover(); r != nil { + var ok bool + if err, ok = r.(error); !ok { + err = fmt.Errorf("%v", r) + } + err = fmt.Errorf("panic occurred during encoding message %s: %v", msg.GetMessageName(), err) + } + }() + + marshaller, ok := msg.(Marshaler) + if !ok { + marshaller = Wrapper{msg} } - // encode message content - if reflect.Indirect(reflect.ValueOf(msg)).NumField() > 0 { - err := struc.Pack(buf, msg) - if err != nil { - return nil, fmt.Errorf("unable to encode message: header %v, error %v", header, err) - } + size := marshaller.Size() + offset := getOffset(msg) + + // encode msg ID + b := make([]byte, size+offset) + b[0] = byte(msgID >> 8) + b[1] = byte(msgID) + + data, err = marshaller.Marshal(b[offset:]) + if err != nil { + return nil, err } - return buf.Bytes(), nil + return b[0:len(b):len(b)], nil } -// DecodeMsg decodes binary-encoded data of a message into provided `Message` structure. -func (*MsgCodec) DecodeMsg(data []byte, msg api.Message) error { +func (*MsgCodec) DecodeMsg(data []byte, msg api.Message) (err error) { if msg == nil { return errors.New("nil message passed in") } - buf := bytes.NewReader(data) - - // check which header is expected - var header interface{} - if msg.GetMessageType() == api.RequestMessage { - header = &VppRequestHeader{} - } else if msg.GetMessageType() == api.ReplyMessage { - header = &VppReplyHeader{} - } else if msg.GetMessageType() == api.EventMessage { - header = &VppEventHeader{} - } else { - header = &VppOtherHeader{} - } + // try to recover panic which might possibly occur + defer func() { + if r := recover(); r != nil { + var ok bool + if err, ok = r.(error); !ok { + err = fmt.Errorf("%v", r) + } + err = fmt.Errorf("panic occurred during decoding message %s: %v", msg.GetMessageName(), err) + } + }() - // decode message header - err := struc.Unpack(buf, header) - if err != nil { - return fmt.Errorf("unable to decode message: data %v, error %v", data, err) + marshaller, ok := msg.(Unmarshaler) + if !ok { + marshaller = Wrapper{msg} } - // get rid of the message header - if msg.GetMessageType() == api.RequestMessage { - buf = bytes.NewReader(data[vppRequestHeaderSize:]) - } else if msg.GetMessageType() == api.ReplyMessage { - buf = bytes.NewReader(data[vppReplyHeaderSize:]) - } else if msg.GetMessageType() == api.EventMessage { - buf = bytes.NewReader(data[vppEventHeaderSize:]) - } else { - buf = bytes.NewReader(data[vppOtherHeaderSize:]) - } + offset := getOffset(msg) - // decode message content - err = struc.Unpack(buf, msg) + err = marshaller.Unmarshal(data[offset:len(data)]) if err != nil { - return fmt.Errorf("unable to decode message: data %v, error %v", data, err) + return err } return nil } + +func (*MsgCodec) DecodeMsgContext(data []byte, msgType api.MessageType) (context uint32, err error) { + switch msgType { + case api.RequestMessage: + return binary.BigEndian.Uint32(data[6:10]), nil + case api.ReplyMessage: + return binary.BigEndian.Uint32(data[2:6]), nil + } + + return 0, nil +} + +func getOffset(msg api.Message) (offset int) { + switch msg.GetMessageType() { + case api.RequestMessage: + return 10 + case api.ReplyMessage: + return 6 + case api.EventMessage: + return 6 + } + return 2 +}