6534e7d175bc85a875b807b79e48a8dbdff29403
[govpp.git] / codec / msg_codec.go
1 // Copyright (c) 2017 Cisco and/or its affiliates.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at:
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 package codec
16
17 import (
18         "encoding/binary"
19         "errors"
20         "fmt"
21
22         "git.fd.io/govpp.git/api"
23 )
24
25 var DefaultCodec = new(MsgCodec)
26
27 func EncodeMsg(msg api.Message, msgID uint16) (data []byte, err error) {
28         return DefaultCodec.EncodeMsg(msg, msgID)
29 }
30 func DecodeMsg(data []byte, msg api.Message) (err error) {
31         return DefaultCodec.DecodeMsg(data, msg)
32 }
33 func DecodeMsgContext(data []byte, msg api.Message) (context uint32, err error) {
34         return DefaultCodec.DecodeMsgContext(data, msg)
35 }
36
37 // MsgCodec provides encoding and decoding functionality of `api.Message` structs into/from
38 // binary format as accepted by VPP.
39 type MsgCodec struct{}
40
41 func (*MsgCodec) EncodeMsg(msg api.Message, msgID uint16) (data []byte, err error) {
42         if msg == nil {
43                 return nil, errors.New("nil message passed in")
44         }
45
46         // try to recover panic which might possibly occur
47         defer func() {
48                 if r := recover(); r != nil {
49                         var ok bool
50                         if err, ok = r.(error); !ok {
51                                 err = fmt.Errorf("%v", r)
52                         }
53                         err = fmt.Errorf("panic occurred during encoding message %s: %v", msg.GetMessageName(), err)
54                 }
55         }()
56
57         marshaller, ok := msg.(Marshaler)
58         if !ok {
59                 marshaller = Wrapper{msg}
60         }
61
62         size := marshaller.Size()
63         offset := getOffset(msg)
64
65         // encode msg ID
66         b := make([]byte, size+offset)
67         b[0] = byte(msgID >> 8)
68         b[1] = byte(msgID)
69
70         data, err = marshaller.Marshal(b[offset:])
71         if err != nil {
72                 return nil, err
73         }
74
75         return b[0:len(b):len(b)], nil
76 }
77
78 func (*MsgCodec) DecodeMsg(data []byte, msg api.Message) (err error) {
79         if msg == nil {
80                 return errors.New("nil message passed in")
81         }
82
83         // try to recover panic which might possibly occur
84         defer func() {
85                 if r := recover(); r != nil {
86                         var ok bool
87                         if err, ok = r.(error); !ok {
88                                 err = fmt.Errorf("%v", r)
89                         }
90                         err = fmt.Errorf("panic occurred during decoding message %s: %v", msg.GetMessageName(), err)
91                 }
92         }()
93
94         marshaller, ok := msg.(Unmarshaler)
95         if !ok {
96                 marshaller = Wrapper{msg}
97         }
98
99         offset := getOffset(msg)
100
101         err = marshaller.Unmarshal(data[offset:len(data)])
102         if err != nil {
103                 return err
104         }
105
106         return nil
107 }
108
109 func (*MsgCodec) DecodeMsgContext(data []byte, msg api.Message) (context uint32, err error) {
110         if msg == nil {
111                 return 0, errors.New("nil message passed in")
112         }
113
114         switch msg.GetMessageType() {
115         case api.RequestMessage:
116                 return binary.BigEndian.Uint32(data[6:10]), nil
117         case api.ReplyMessage:
118                 return binary.BigEndian.Uint32(data[2:6]), nil
119         }
120
121         return 0, nil
122 }
123
124 func getOffset(msg api.Message) (offset int) {
125         switch msg.GetMessageType() {
126         case api.RequestMessage:
127                 return 10
128         case api.ReplyMessage:
129                 return 6
130         case api.EventMessage:
131                 return 6
132         }
133         return 2
134 }