import sirupsen with lowercase
[govpp.git] / core / 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 core
16
17 import (
18         "bytes"
19         "errors"
20         "fmt"
21         "reflect"
22
23         "github.com/lunixbochs/struc"
24         logger "github.com/sirupsen/logrus"
25
26         "git.fd.io/govpp.git/api"
27 )
28
29 // MsgCodec provides encoding and decoding functionality of `api.Message` structs into/from
30 // binary format as accepted by VPP.
31 type MsgCodec struct{}
32
33 // vppRequestHeader struct contains header fields implemented by all VPP requests.
34 type vppRequestHeader struct {
35         VlMsgID     uint16
36         ClientIndex uint32
37         Context     uint32
38 }
39
40 // vppReplyHeader struct contains header fields implemented by all VPP replies.
41 type vppReplyHeader struct {
42         VlMsgID uint16
43         Context uint32
44 }
45
46 // vppOtherHeader struct contains header fields implemented by other VPP messages (not requests nor replies).
47 type vppOtherHeader struct {
48         VlMsgID uint16
49 }
50
51 const (
52         vppRequestHeaderSize = 10 // size of a VPP request header
53         vppReplyHeaderSize   = 6  // size of a VPP reply header
54         vppOtherHeaderSize   = 2  // size of the header of other VPP messages
55 )
56
57 // EncodeMsg encodes provided `Message` structure into its binary-encoded data representation.
58 func (*MsgCodec) EncodeMsg(msg api.Message, msgID uint16) ([]byte, error) {
59         if msg == nil {
60                 return nil, errors.New("nil message passed in")
61         }
62
63         buf := new(bytes.Buffer)
64
65         // encode message header
66         var header interface{}
67         if msg.GetMessageType() == api.RequestMessage {
68                 header = &vppRequestHeader{VlMsgID: msgID}
69         } else if msg.GetMessageType() == api.ReplyMessage {
70                 header = &vppReplyHeader{VlMsgID: msgID}
71         } else {
72                 header = &vppOtherHeader{VlMsgID: msgID}
73         }
74         err := struc.Pack(buf, header)
75         if err != nil {
76                 log.WithFields(logger.Fields{
77                         "error":  err,
78                         "header": header,
79                 }).Error("Unable to encode the message header: ", err)
80                 return nil, fmt.Errorf("unable to encode the message header: %v", err)
81         }
82
83         // encode message content
84         if reflect.Indirect(reflect.ValueOf(msg)).NumField() > 0 {
85                 err := struc.Pack(buf, msg)
86                 if err != nil {
87                         log.WithFields(logger.Fields{
88                                 "error":   err,
89                                 "message": msg,
90                         }).Error("Unable to encode the message: ", err)
91                         return nil, fmt.Errorf("unable to encode the message: %v", err)
92                 }
93         }
94
95         return buf.Bytes(), nil
96 }
97
98 // DecodeMsg decodes binary-encoded data of a message into provided `Message` structure.
99 func (*MsgCodec) DecodeMsg(data []byte, msg api.Message) error {
100         if msg == nil {
101                 return errors.New("nil message passed in")
102         }
103
104         buf := bytes.NewReader(data)
105
106         // check which header is expected
107         var header interface{}
108         if msg.GetMessageType() == api.RequestMessage {
109                 header = &vppRequestHeader{}
110         } else if msg.GetMessageType() == api.ReplyMessage {
111                 header = &vppReplyHeader{}
112         } else {
113                 header = &vppOtherHeader{}
114         }
115
116         // decode message header
117         err := struc.Unpack(buf, header)
118         if err != nil {
119                 log.WithFields(logger.Fields{
120                         "error": err,
121                         "data":  data,
122                 }).Error("Unable to decode header of the message.")
123                 return fmt.Errorf("unable to decode the message header: %v", err)
124         }
125
126         // get rid of the message header
127         if msg.GetMessageType() == api.RequestMessage {
128                 buf = bytes.NewReader(data[vppRequestHeaderSize:])
129         } else if msg.GetMessageType() == api.ReplyMessage {
130                 buf = bytes.NewReader(data[vppReplyHeaderSize:])
131         } else {
132                 buf = bytes.NewReader(data[vppOtherHeaderSize:])
133         }
134
135         // decode message content
136         err = struc.Unpack(buf, msg)
137         if err != nil {
138                 log.WithFields(logger.Fields{
139                         "error": err,
140                         "data":  buf,
141                 }).Error("Unable to decode the message.")
142                 return fmt.Errorf("unable to decode the message: %v", err)
143         }
144
145         return nil
146 }